diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6951c29 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.idea/ +/.settings/ +java-chat.iml diff --git a/pom.xml b/pom.xml index 05188ae..21c5d05 100644 --- a/pom.xml +++ b/pom.xml @@ -3,4 +3,22 @@ org.progmethoden java-chat 0.0.1-SNAPSHOT + + + + + com.google.code.gson + gson + 2.10.1 + + + + org.mockito + mockito-core + 4.1.10 + test + + + + \ No newline at end of file diff --git a/src/main/java/ChatClient.java b/src/main/java/ChatClient.java new file mode 100644 index 0000000..30b486c --- /dev/null +++ b/src/main/java/ChatClient.java @@ -0,0 +1,112 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.io.*; +import java.net.Socket; + +public class ChatClient extends JFrame implements KeyListener { + private String address; + private String connectionFailedMessage; + private Socket connectionToServer; + private BufferedReader fromServerReader; + private PrintWriter toServerWriter; + + // GUI + private JTextArea outputTextArea; + private JTextField inputTextField; + private JScrollPane outputScrollPane; + + public ChatClient() { + super("Chat"); + address = JOptionPane.showInputDialog("bitte IP-Adresse"); + if (null != address) { + connectionFailedMessage = "Verbindung zum Server " + (address.isEmpty() ? "" : ("\"" + address + "\"")) + " fehlgeschlagen."; + receiveMessages(); + } + } + + private void initGui() { + outputTextArea = new JTextArea(); + outputTextArea.setEditable(false); + outputTextArea.setBorder(BorderFactory.createTitledBorder("Chat")); + + outputScrollPane = new JScrollPane(outputTextArea); + + inputTextField = new JTextField(); + inputTextField.setBorder(BorderFactory.createTitledBorder("Nachricht eingeben")); + inputTextField.addKeyListener(this); + + add(outputScrollPane, BorderLayout.CENTER); + add(inputTextField, BorderLayout.SOUTH); + + setVisible(true); + setSize(Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setLocationRelativeTo(null); + } + private void receiveMessages() { + try { + connectionToServer = new Socket(address, Constants.PORT); + fromServerReader = new BufferedReader(new InputStreamReader(connectionToServer.getInputStream())); + toServerWriter = new PrintWriter(new OutputStreamWriter(connectionToServer.getOutputStream())); + + initGui(); + + while (true) { + String message = fromServerReader.readLine(); + outputTextArea.append(message + "\n"); + outputScrollPane.getVerticalScrollBar().setValue(outputScrollPane.getVerticalScrollBar().getMaximum()); + } + } catch (IOException e) { + JOptionPane.showMessageDialog(null, connectionFailedMessage); + dispose(); + } finally { + if (null != connectionToServer) { + try { + connectionToServer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (null != fromServerReader) { + try { + fromServerReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if(null != toServerWriter) { + toServerWriter.close(); + } + } + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + String message = inputTextField.getText(); + if (!message.isEmpty()) { + toServerWriter.println(message); + toServerWriter.flush(); + inputTextField.setText(""); + } + } + } + + @Override + public void keyReleased(KeyEvent e) { + + } + + public static void main(String[] args) { + new ChatClient(); + } +} diff --git a/src/main/java/ChatServer.java b/src/main/java/ChatServer.java new file mode 100644 index 0000000..0c60774 --- /dev/null +++ b/src/main/java/ChatServer.java @@ -0,0 +1,60 @@ + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class ChatServer { + private ServerSocket serverSocket; + private List clients; // Liste, um alle verbundenen Clients zu verwalten + + public ChatServer(int port) { + clients = new CopyOnWriteArrayList<>(); // Verwende CopyOnWriteArrayList für die Thread-Sicherheit + + try { + serverSocket = new ServerSocket(port); + System.out.println("Started ChatServer on port " + port); + + while (true) { + System.out.println("waiting for new Client..."); + Socket connectionToClient = serverSocket.accept(); // Auf Verbindungen von Clients warten + ClientHandler client = new ClientHandler(this, connectionToClient); + clients.add(client); // Neuen Client zur Liste hinzufügen + System.out.println("Accepted new Client"); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + } + // Methode, um eine Nachricht an alle verbundenen Clients zu senden + public void broadcastMessage(String message) { + System.out.println(message); + if (message != null) { + for (ClientHandler client : clients) { + client.sendMessage(message); // Nachricht an jeden Client senden + } + } + + } + + public static void main(String[] args) { + new ChatServer(3141); // ChatServer auf Port 3141 starten (eventuell den Port flexibler noch wählen? falls belegt) + + } + // Methode, um einen Client aus der Liste der verbundenen Clients zu entfernen + public void removeClient(ClientHandler client) { + clients.remove(client); + } + +} \ No newline at end of file diff --git a/src/main/java/ClientHandler.java b/src/main/java/ClientHandler.java new file mode 100644 index 0000000..74fa305 --- /dev/null +++ b/src/main/java/ClientHandler.java @@ -0,0 +1,65 @@ +import java.io.*; +import java.net.Socket; + +public class ClientHandler implements Runnable { + private ChatServer chatServer; + private Socket connectionToClient; + private String name; + private BufferedReader fromClientReader; + private PrintWriter toClientWriter; + + // Constructor for ClientHandler + public ClientHandler(ChatServer chatServer, Socket connectionToClient) { + this.chatServer = chatServer; + this.connectionToClient = connectionToClient; + name = connectionToClient.getInetAddress().getHostAddress(); // Use the client's IP address as their name for simplicity + + new Thread(this).start();} // Start a new thread for this client handler + + @Override + public void run() { + + try { + // Set up input and output streams for communication with the client + fromClientReader = new BufferedReader (new InputStreamReader(connectionToClient.getInputStream())); + toClientWriter = new PrintWriter (new OutputStreamWriter(connectionToClient.getOutputStream())); + + chatServer.broadcastMessage(name + " connected."); // Broadcast a message when the client is connected + + // Read messages from the client and broadcast them to all clients + String message = fromClientReader.readLine(); + while (message!=null) { + // Broadcast the client's message to all connected clients + chatServer.broadcastMessage(name + ": " + message); + message = fromClientReader.readLine(); + } + } + + catch (IOException e) { + throw new RuntimeException(e); // Handle exceptions by throwing a runtime exception + } + finally { + chatServer.removeClient(this); + chatServer.broadcastMessage(name + " disconnected."); // Broadcast a message when the client is disconnected + + // Close resources in the finally block + if (fromClientReader != null) { + try { + fromClientReader.close(); + } + catch (IOException e){ + e.printStackTrace(); + } + } + if (toClientWriter != null) { + toClientWriter.close(); + } + } + } + + //Method to send a message to the client + public void sendMessage(String message) { + toClientWriter.println(message); // Send the message to the client + toClientWriter.flush(); // Flush the stream + } +} diff --git a/src/main/java/Constants.java b/src/main/java/Constants.java new file mode 100644 index 0000000..5848138 --- /dev/null +++ b/src/main/java/Constants.java @@ -0,0 +1,5 @@ +public class Constants { + public static final int WINDOW_WIDTH = 800; + public static final int WINDOW_HEIGHT = 600; + public static final int PORT = 3141; +} diff --git a/src/main/java/CreateUser.java b/src/main/java/CreateUser.java new file mode 100644 index 0000000..c799654 --- /dev/null +++ b/src/main/java/CreateUser.java @@ -0,0 +1,155 @@ +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import java.io.*; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import java.io.FileWriter; +import java.io.IOException; + +import java.util.UUID; + +class CreateUser { + private String id; + private String userName; + private String password; + private String birthday; + private boolean stayLoggedIn; + + + // Constructor + public CreateUser(String id, String name, String password, String birthday) { + this.id = id; + this.userName = name; + this.password = password; + this.birthday = birthday; + } + + // Getters and Setters + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getBirthday() { + return birthday; + } + + public void setBirthday(String birthday) { + this.birthday = birthday; + } + + public boolean isStayLoggedIn() { + return stayLoggedIn; + } + + public void setStayLoggedIn(boolean stayLoggedIn) { + this.stayLoggedIn = stayLoggedIn; + } + + // Function to create user with validation + public static CreateUser createUser(String id, String userName, String password, String birthday) { + if (userName == null || userName.isEmpty()) { + throw new IllegalArgumentException("Username cannot be empty"); + } + if (password == null || password.isEmpty()) { + throw new IllegalArgumentException("Password cannot be empty"); + } + if (password.length() < 6) { + throw new IllegalArgumentException("Password must be at least 6 characters long"); + } return new CreateUser(id, userName, password, birthday); + } + + // Function to save to JSON file, replace with database call later + public void saveToJsonFile(String filename) { + List userList = readUserListFromJsonFile(filename); + userList.add(this); + + try (FileWriter fileWriter = new FileWriter(filename)) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + gson.toJson(userList, fileWriter); + System.out.println("User information appended to " + filename); + } catch (IOException e) { + System.out.println("Error occurred while saving user information to JSON file: " + e.getMessage()); + } + } + + // Function to read user information from a JSON file + public static List readUserListFromJsonFile(String filename) { + List userList = new ArrayList<>(); + try (Reader reader = new FileReader(filename)) { + Type userListType = new TypeToken>() {}.getType(); + Gson gson = new Gson(); + userList = gson.fromJson(reader, userListType); + } catch (FileNotFoundException e) { + // File does not exist yet, so return an empty list + } catch (IOException e) { + System.out.println("Error occurred while reading user information from JSON file: " + e.getMessage()); + } + return userList; + } + + // Function to update stayLoggedIn variable in the JSON file + public static void updateStayLoggedIn(String filename, String username, boolean stayLoggedIn) { + List userList = readUserListFromJsonFile(filename); + + for (CreateUser user : userList) { + if (user.getUserName().equals(username)) { + user.setStayLoggedIn(stayLoggedIn); + break; + } + } + + try (FileWriter fileWriter = new FileWriter(filename)) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + gson.toJson(userList, fileWriter); + System.out.println("StayLoggedIn updated in " + filename); + } catch (IOException e) { + System.out.println("Error occurred while updating StayLoggedIn in JSON file: " + e.getMessage()); + } + } + + public static void main(String[] args) { + try { + // Example usage + UUID randomUUID = UUID.randomUUID(); + CreateUser user = createUser(randomUUID.toString(), "Test User", "TestPasswort123", "01.01.2000"); + + // Example of accessing properties + System.out.println("UserID: " + user.getId()); + System.out.println("User Name: " + user.getUserName()); + System.out.println("User Password: " + user.getPassword()); + System.out.println("User Birthday: " + user.getBirthday()); + + + // Save user information to a JSON file + user.saveToJsonFile("user.json"); + + updateStayLoggedIn("user.json", "Test User", true); + } catch (IllegalArgumentException e) { + System.out.println("Error: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/LoginGUI.java b/src/main/java/LoginGUI.java new file mode 100644 index 0000000..675ffa5 --- /dev/null +++ b/src/main/java/LoginGUI.java @@ -0,0 +1,122 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class LoginGUI extends JFrame implements ActionListener { + private JTextField usernameField; + private JPasswordField passwordField; + private JButton loginButton; + private JCheckBox stayLoggedInCheckbox; + + public LoginGUI() { + setTitle("Login"); + setSize(300, 180); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setLayout(null); + + JLabel usernameLabel = new JLabel("Username:"); + usernameLabel.setBounds(20, 20, 80, 25); + add(usernameLabel); + + usernameField = new JTextField(); + usernameField.setBounds(100, 20, 160, 25); + add(usernameField); + + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setBounds(20, 50, 80, 25); + add(passwordLabel); + + passwordField = new JPasswordField(); + passwordField.setBounds(100, 50, 160, 25); + add(passwordField); + + stayLoggedInCheckbox = new JCheckBox("Stay Logged In"); + stayLoggedInCheckbox.setBounds(20, 80, 150, 25); + add(stayLoggedInCheckbox); + + loginButton = new JButton("Login"); + loginButton.setBounds(100, 110, 100, 25); + loginButton.addActionListener(this); + add(loginButton); + + getRootPane().setDefaultButton(loginButton); + + passwordField.addKeyListener(new EnterKeyListener()); + + stayLoggedInCheckbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean stayLoggedIn = stayLoggedInCheckbox.isSelected(); + String username = usernameField.getText(); + updateStayLoggedIn(username, stayLoggedIn); + } + }); + + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == loginButton) { + login(); + } + } + + private void login() { + String username = usernameField.getText(); + String password = new String(passwordField.getPassword()); + boolean stayLoggedIn = stayLoggedInCheckbox.isSelected(); // Get checkbox state + + if (authenticateUser(username, password)) { + JOptionPane.showMessageDialog(this, "Login successful!"); + // Perform actions after successful login + + dispose(); + } else { + JOptionPane.showMessageDialog(this, "Invalid username or password", "Login Error", JOptionPane.ERROR_MESSAGE); + } + } + + private void updateStayLoggedIn(String username, boolean stayLoggedIn) { + // Update stayLoggedIn in the JSON file for the user + CreateUser.updateStayLoggedIn("user.json", username, stayLoggedIn); + } + + // Function to authenticate the user by comparing the entered username and password with the saved user data + private boolean authenticateUser(String username, String password) { + List userList = CreateUser.readUserListFromJsonFile("user.json"); + if (userList != null) { + for (CreateUser user : userList) { + if (user.getUserName().equals(username) && user.getPassword().equals(password)) { + return true; //Success + } + } + } + return false; // Fail + } + + + private class EnterKeyListener implements KeyListener { + @Override + public void keyTyped(KeyEvent e) {} + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + login(); + } + } + + @Override + public void keyReleased(KeyEvent e) {} + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + LoginGUI loginGUI = new LoginGUI(); + loginGUI.setVisible(true); + }); + } +} \ No newline at end of file diff --git a/src/main/java/SignUpGUI.java b/src/main/java/SignUpGUI.java new file mode 100644 index 0000000..b19cf8e --- /dev/null +++ b/src/main/java/SignUpGUI.java @@ -0,0 +1,103 @@ +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; +import java.util.UUID; + +public class SignUpGUI extends JFrame implements ActionListener { + private JTextField usernameField, passwordField, confirmPasswordField, birthdayField; + private JButton signUpButton; + + public SignUpGUI() { + setTitle("Sign Up"); + setSize(300, 250); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setLayout(null); + + JLabel usernameLabel = new JLabel("Username:"); + usernameLabel.setBounds(20, 20, 80, 25); + add(usernameLabel); + + usernameField = new JTextField(); + usernameField.setBounds(100, 20, 160, 25); + add(usernameField); + + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setBounds(20, 50, 80, 25); + add(passwordLabel); + + passwordField = new JPasswordField(); + passwordField.setBounds(100, 50, 160, 25); + add(passwordField); + + JLabel confirmPasswordLabel = new JLabel("Confirm Password:"); + confirmPasswordLabel.setBounds(20, 80, 120, 25); + add(confirmPasswordLabel); + + confirmPasswordField = new JPasswordField(); + confirmPasswordField.setBounds(140, 80, 120, 25); + add(confirmPasswordField); + + JLabel birthdayLabel = new JLabel("Birthday:"); + birthdayLabel.setBounds(20, 110, 80, 25); + add(birthdayLabel); + + birthdayField = new JTextField(); + birthdayField.setBounds(100, 110, 160, 25); + add(birthdayField); + + signUpButton = new JButton("Sign Up"); + signUpButton.setBounds(100, 150, 100, 25); + signUpButton.addActionListener(this); + add(signUpButton); + + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == signUpButton) { + String username = usernameField.getText(); + String password = passwordField.getText(); + String confirmPassword = confirmPasswordField.getText(); + String birthday = birthdayField.getText(); + + if (!password.equals(confirmPassword)) { + JOptionPane.showMessageDialog(this, "Passwords do not match!", "Sign Up Error", JOptionPane.ERROR_MESSAGE); + return; + } + + if (!isUsernameAvailable("user.json", username)) { + JOptionPane.showMessageDialog(this, "Username already exists!", "Sign Up Error", JOptionPane.ERROR_MESSAGE); + return; + } + try { + UUID randomUUID = UUID.randomUUID(); + CreateUser user = CreateUser.createUser(randomUUID.toString(), username, password, birthday); + user.saveToJsonFile("user.json"); + JOptionPane.showMessageDialog(this, "User signed up successfully!"); + dispose(); + } catch (IllegalArgumentException ex) { + JOptionPane.showMessageDialog(this, "Error: " + ex.getMessage(), "Sign Up Error", JOptionPane.ERROR_MESSAGE); + } + } + } + // Function to check if the input username doesn't already exist in the JSON file + private boolean isUsernameAvailable(String filename, String username) { + List userList = CreateUser.readUserListFromJsonFile(filename); + if (userList != null) { + for (CreateUser user : userList) { + if (user.getUserName().equals(username)) { + return false; // Username already exists + } + } + } + return true; // Username is available + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + SignUpGUI signUpGUI = new SignUpGUI(); + signUpGUI.setVisible(true); + }); + } +} \ No newline at end of file diff --git a/src/main/java/test b/src/main/java/test deleted file mode 100644 index e69de29..0000000 diff --git a/user.json b/user.json new file mode 100644 index 0000000..5437c96 --- /dev/null +++ b/user.json @@ -0,0 +1,23 @@ +[ + { + "id": "a2864d79-1079-4cbb-8d77-f5f84995580d", + "userName": "Another Test User", + "password": "TestPasswort123", + "birthday": "01.01.2000", + "stayLoggedIn": false + }, + { + "id": "3690702d-9c7e-48fb-8a01-ef89b3b76268", + "userName": "TestUser2", + "password": "123456", + "birthday": "01.01.2000", + "stayLoggedIn": false + }, + { + "id": "685bc3a6-e706-4214-a5e1-8443d1a5258e", + "userName": "Test User", + "password": "Test", + "birthday": "01.01.2000", + "stayLoggedIn": true + } +] \ No newline at end of file