From 8714c8fe0e4e3fa4b14f0627bef5794e872a2ac5 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 12 Feb 2020 17:31:20 +0100 Subject: [PATCH] Performing handshake and online init in LoginDialog --- src/main/java/envoy/client/net/Receiver.java | 2 +- .../java/envoy/client/ui/LoginDialog.java | 337 ++++++++++-------- src/main/java/envoy/client/ui/Startup.java | 46 +-- 3 files changed, 205 insertions(+), 180 deletions(-) diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 25e7153..d8a0d45 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -51,7 +51,7 @@ public class Receiver implements Runnable { try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objBytes))) { Object obj = oin.readObject(); - logger.finest("Received object " + obj); + logger.info("Received object " + obj); // Get appropriate processor @SuppressWarnings("rawtypes") diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index d9e4750..bdac73a 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -2,17 +2,25 @@ package envoy.client.ui; import java.awt.*; import java.awt.event.ItemEvent; +import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.logging.Logger; +import javax.naming.TimeLimitExceededException; import javax.swing.*; import javax.swing.border.EmptyBorder; -import envoy.client.data.Settings; +import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; +import envoy.client.net.Client; +import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; +import envoy.data.Message; +import envoy.data.User; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; +import envoy.exception.EnvoyException; /** * Project: envoy-client
@@ -25,7 +33,7 @@ import envoy.event.HandshakeRejectionEvent; */ public class LoginDialog extends JDialog { - private final JPanel contentPanel; + private JPanel contentPanel; private JTextField textField; private JPasswordField passwordField; private JPasswordField repeatPasswordField; @@ -47,14 +55,111 @@ public class LoginDialog extends JDialog { private LoginCredentials credentials; - private static final long serialVersionUID = 352021600833907468L; + private final Client client; + private final LocalDb localDb; + private final Cache receivedMessageCache; + + private static final Config config = Config.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class.getSimpleName()); + private static final long serialVersionUID = 352021600833907468L; /** * Displays a dialog enabling the user to enter their user name and password. * + * @param client the client used to perform the handshake + * @param localDb the local database in which data is persisted + * @param receivedMessageCache the cache that stored messages received during + * the handshake * @since Envoy v0.3-alpha */ - public LoginDialog() { + public LoginDialog(Client client, LocalDb localDb, Cache receivedMessageCache) { + this.client = client; + this.localDb = localDb; + this.receivedMessageCache = receivedMessageCache; + + // Prepare handshake + localDb.loadIdGenerator(); + + initUi(); + + okButton.addActionListener((evt) -> { + try { + if (registerCheckBox.isSelected()) { + // Check password equality + if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); + else { + JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); + clearPasswordFields(); + } + } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); + performHandshake(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + }); + + // Listen to handshake rejections + EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { + for (Component c : contentPanel.getComponents()) + if (c == errorMessage) contentPanel.remove(errorMessage); + clearPasswordFields(); + errorMessage = new JLabel(evt.get()); + gbc_errorMessage = new GridBagConstraints(); + gbc_errorMessage.gridx = 2; + gbc_errorMessage.gridy = 0; + gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; + gbc_errorMessage.insets = new Insets(5, 5, 5, 5); + contentPanel.add(errorMessage, gbc_errorMessage); + contentPanel.revalidate(); + contentPanel.repaint(); + }); + + // Exit the application when the dialog is cancelled + cancelButton.addActionListener(evt -> { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); }); + + // Log in directly if configured + if (config.hasLoginCredentials()) { + credentials = config.getLoginCredentials(); + performHandshake(); + return; + } + + setVisible(true); + } + + private void performHandshake() { + try { + client.performHandshake(credentials, receivedMessageCache); + if (client.isOnline()) { + client.initReceiver(localDb, receivedMessageCache); + dispose(); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } catch (TimeLimitExceededException e) { + logger.warning("Could not connect to server. Trying offline mode..."); + e.printStackTrace(); + try { + // Try entering offline mode + localDb.loadUsers(); + User clientUser = localDb.getUsers().get(credentials.getIdentifier()); + if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); + client.setSender(clientUser); + JOptionPane.showMessageDialog(null, + "A connection to the server could not be established. Starting in offline mode.\n" + e, + "Connection error", + JOptionPane.WARNING_MESSAGE); + dispose(); + } catch (Exception e1) { + JOptionPane.showMessageDialog(null, e1, "Client error", JOptionPane.ERROR_MESSAGE); + System.exit(1); + return; + } + } + } + + private void initUi() { setSize(338, 123); setLocationRelativeTo(null); getContentPane().setLayout(new BorderLayout()); @@ -67,150 +172,109 @@ public class LoginDialog extends JDialog { gbl_contentPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; contentPanel.setLayout(gbl_contentPanel); - { - lblUserName = new JLabel("Username:"); - GridBagConstraints gbc_lblUserName = new GridBagConstraints(); - gbc_lblUserName.anchor = GridBagConstraints.EAST; - gbc_lblUserName.insets = new Insets(0, 0, 5, 5); - gbc_lblUserName.gridx = 0; - gbc_lblUserName.gridy = 0; - contentPanel.add(lblUserName, gbc_lblUserName); - } - { - textField = new JTextField(); - textField.setBorder(null); - GridBagConstraints gbc_textField = new GridBagConstraints(); - gbc_textField.insets = new Insets(0, 0, 5, 0); - gbc_textField.fill = GridBagConstraints.HORIZONTAL; - gbc_textField.gridx = 1; - gbc_textField.gridy = 0; - contentPanel.add(textField, gbc_textField); - textField.setColumns(10); - } - { - lblPassword = new JLabel("Password:"); - GridBagConstraints gbc_lblPassword = new GridBagConstraints(); - gbc_lblPassword.anchor = GridBagConstraints.EAST; - gbc_lblPassword.insets = new Insets(0, 0, 0, 5); - gbc_lblPassword.gridx = 0; - gbc_lblPassword.gridy = 1; - contentPanel.add(lblPassword, gbc_lblPassword); - } - { - passwordField = new JPasswordField(); - passwordField.setBorder(null); - GridBagConstraints gbc_passwordField = new GridBagConstraints(); - gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField.gridx = 1; - gbc_passwordField.gridy = 1; - contentPanel.add(passwordField, gbc_passwordField); - } - { - lblRepeatPassword = new JLabel("Repeat Password:"); - gbc_lblRepeatPassword = new GridBagConstraints(); - gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; - gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); - gbc_lblRepeatPassword.gridx = 0; - gbc_lblRepeatPassword.gridy = 2; - } - { - repeatPasswordField = new JPasswordField(); - gbc_repeatPasswordField = new GridBagConstraints(); - gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; - gbc_repeatPasswordField.gridx = 1; - gbc_repeatPasswordField.gridy = 2; - } - { - EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { - contentPanel.remove(errorMessage); - clearPasswordFields(); - // TODO delete - only for testing purposes - System.out.println("Caught HandshakeRejectionEvent with reason" + evt.get()); - errorMessage = new JLabel(evt.get()); - gbc_errorMessage = new GridBagConstraints(); - gbc_errorMessage.gridx = 2; - gbc_errorMessage.gridy = 0; - gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; - gbc_errorMessage.insets = new Insets(5, 5, 5, 5); - contentPanel.add(errorMessage, gbc_errorMessage); - }); - } - { - buttonPane = new JPanel(); - registerText = new JTextPane(); - registerText.setEditable(false); - registerText.setText("Register?"); - registerText.setFont(new Font("Arial", Font.BOLD, 12)); - registerText.setAlignmentX(LEFT_ALIGNMENT); - buttonPane.add(registerText); + lblUserName = new JLabel("Username:"); + GridBagConstraints gbc_lblUserName = new GridBagConstraints(); + gbc_lblUserName.anchor = GridBagConstraints.EAST; + gbc_lblUserName.insets = new Insets(0, 0, 5, 5); + gbc_lblUserName.gridx = 0; + gbc_lblUserName.gridy = 0; + contentPanel.add(lblUserName, gbc_lblUserName); - registerCheckBox = new JCheckBox(); - registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); - registerCheckBox.addItemListener(e -> { - switch (e.getStateChange()) { - case ItemEvent.SELECTED: - contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); - contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); - setSize(338, 148); - break; + textField = new JTextField(); + textField.setBorder(null); + GridBagConstraints gbc_textField = new GridBagConstraints(); + gbc_textField.insets = new Insets(0, 0, 5, 0); + gbc_textField.fill = GridBagConstraints.HORIZONTAL; + gbc_textField.gridx = 1; + gbc_textField.gridy = 0; + contentPanel.add(textField, gbc_textField); + textField.setColumns(10); - case ItemEvent.DESELECTED: - if (repeatPasswordField.getParent() == contentPanel) { - contentPanel.remove(lblRepeatPassword); - contentPanel.remove(repeatPasswordField); - setSize(338, 123); - } - break; - } - contentPanel.revalidate(); - contentPanel.repaint(); - }); - buttonPane.add(registerCheckBox); + lblPassword = new JLabel("Password:"); + GridBagConstraints gbc_lblPassword = new GridBagConstraints(); + gbc_lblPassword.anchor = GridBagConstraints.EAST; + gbc_lblPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblPassword.gridx = 0; + gbc_lblPassword.gridy = 1; + contentPanel.add(lblPassword, gbc_lblPassword); - buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); - getContentPane().add(buttonPane, BorderLayout.SOUTH); - { - okButton = new PrimaryButton("OK"); - okButton.addActionListener((evt) -> { - try { - if (registerCheckBox.isSelected()) { - // password checking - if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) - credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); - else { - JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); - clearPasswordFields(); - } - } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); + passwordField = new JPasswordField(); + passwordField.setBorder(null); + GridBagConstraints gbc_passwordField = new GridBagConstraints(); + gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; + gbc_passwordField.gridx = 1; + gbc_passwordField.gridy = 1; + contentPanel.add(passwordField, gbc_passwordField); + + lblRepeatPassword = new JLabel("Repeat Password:"); + gbc_lblRepeatPassword = new GridBagConstraints(); + gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; + gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblRepeatPassword.gridx = 0; + gbc_lblRepeatPassword.gridy = 2; + + repeatPasswordField = new JPasswordField(); + gbc_repeatPasswordField = new GridBagConstraints(); + gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; + gbc_repeatPasswordField.gridx = 1; + gbc_repeatPasswordField.gridy = 2; + + buttonPane = new JPanel(); + + registerText = new JTextPane(); + registerText.setEditable(false); + registerText.setText("Register?"); + registerText.setFont(new Font("Arial", Font.BOLD, 12)); + registerText.setAlignmentX(LEFT_ALIGNMENT); + buttonPane.add(registerText); + + registerCheckBox = new JCheckBox(); + registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); + registerCheckBox.addItemListener(e -> { + switch (e.getStateChange()) { + case ItemEvent.SELECTED: + contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); + contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); + setSize(338, 148); + break; + + case ItemEvent.DESELECTED: + if (repeatPasswordField.getParent() == contentPanel) { + contentPanel.remove(lblRepeatPassword); + contentPanel.remove(repeatPasswordField); + setSize(338, 123); } - }); - okButton.setActionCommand("OK"); - buttonPane.add(okButton); - getRootPane().setDefaultButton(okButton); + break; } - { - cancelButton = new PrimaryButton("Cancel"); - cancelButton.addActionListener((evt) -> dispose()); - cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton); - } - } + contentPanel.revalidate(); + contentPanel.repaint(); + }); + buttonPane.add(registerCheckBox); + + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + okButton = new PrimaryButton("OK"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + + cancelButton = new PrimaryButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); setTheme(); - setModal(true); - setVisible(true); + setModalityType(Dialog.DEFAULT_MODALITY_TYPE); + EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> dispose()); } /** - * Resets the text stored in the passwort fields. + * Resets the text stored in the password fields. * * @since Envoy v0.3-alpha */ - public void clearPasswordFields() { + private void clearPasswordFields() { passwordField.setText(null); repeatPasswordField.setText(null); } @@ -258,11 +322,4 @@ public class LoginDialog extends JDialog { cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); } - - /** - * @return the {@link LoginCredentials} entered by the user, or {@code null} if - * the dialog has been cancelled - * @since Envoy v0.3-alpha - */ - public LoginCredentials getCredentials() { return credentials; } } \ 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 f31cfa3..a684326 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -15,9 +15,7 @@ import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.util.EnvoyLog; -import envoy.data.LoginCredentials; import envoy.data.Message; -import envoy.data.User; import envoy.exception.EnvoyException; /** @@ -74,14 +72,6 @@ public class Startup { EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - // Acquire login credentials - LoginCredentials credentials = config.hasLoginCredentials() ? config.getLoginCredentials() : new LoginDialog().getCredentials(); - - if (credentials == null) { - logger.info("The login process has been cancelled. Exiting..."); - System.exit(0); - } - // Initialize the local database LocalDb localDb; if (config.isIgnoreLocalDB()) { @@ -95,45 +85,23 @@ public class Startup { } catch (IOException e3) { logger.log(Level.SEVERE, "Could not initialize local database", e3); JOptionPane - .showMessageDialog(null, "Could not initialize local database!\n" + e3.toString(), "Local database error", JOptionPane.ERROR_MESSAGE); + .showMessageDialog(null, "Could not initialize local database!\n" + e3, "Local database error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } - SwingUtilities.invokeLater(() -> chatWindow.setVisible(true)); - - // Acquire the client user (with ID) either from the server or from the local - // database, which triggers offline mode + // Initialize client and unread message cache Client client = new Client(); Cache cache = new Cache<>(); - try { - // Try entering online mode first - localDb.loadIdGenerator(); - client.performHandshake(credentials, cache); - client.initReceiver(localDb, cache); - } catch (Exception e1) { - logger.warning("Could not connect to server. Trying offline mode..."); - e1.printStackTrace(); - try { - // Try entering offline mode - localDb.loadUsers(); - User clientUser = localDb.getUsers().get(credentials.getIdentifier()); - if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); - client.setSender(clientUser); - JOptionPane.showMessageDialog(null, - "A connection to the server could not be established. Starting in offline mode.\n" + e1, - "Connection error", - JOptionPane.WARNING_MESSAGE); - } catch (Exception e2) { - JOptionPane.showMessageDialog(null, e2.toString(), "Client error", JOptionPane.ERROR_MESSAGE); - System.exit(1); - return; - } - } + + // Try to connect to the server + new LoginDialog(client, localDb, cache); + SwingUtilities.invokeLater(() -> chatWindow.setVisible(true)); // Set client user in local database localDb.setUser(client.getSender()); + // Initialize chats in local database try { localDb.initializeUserStorage();