# Chat Application

#### **Key Features of the Chat Application**

1. **User**: Represents a user in the system with unique credentials (e.g., phone number, username).
2. **Message**: Represents a chat message that includes the sender, receiver, timestamp, and message content.
3. **ChatRoom**: A chat room represents a group chat where multiple users can send and receive messages.
4. **Real-time Communication**: Facilitates real-time message delivery through sockets (WebSocket or similar).
5. **User Authentication**: Ensures secure login and message exchange with proper authentication.
6. **Message Storage**: Stores sent and received messages in a database.
7. **Message Notifications**: Users are notified in real-time when they receive a new message.

#### **Design Patterns Used**

* **Singleton Pattern**: Used for managing the **ChatRoomManager** class that handles all chat rooms in the system.
* **Factory Pattern**: Used for creating instances of **Message** and **ChatRoom**.
* **Observer Pattern**: Used to notify users when a new message is received in real-time.
* **Command Pattern**: Used to send and receive messages in the system.

***

#### **Code Implementation**

**1. Singleton Pattern - `ChatRoomManager` Class**

The **Singleton Pattern** ensures that there is only one instance of `ChatRoomManager` managing all active chat rooms.

```java
import java.util.HashMap;
import java.util.Map;

// Singleton Pattern to manage active chat rooms
class ChatRoomManager {
    private static ChatRoomManager instance;
    private Map<String, ChatRoom> chatRooms;

    private ChatRoomManager() {
        chatRooms = new HashMap<>();
    }

    // Get the single instance of ChatRoomManager
    public static ChatRoomManager getInstance() {
        if (instance == null) {
            instance = new ChatRoomManager();
        }
        return instance;
    }

    // Create a chat room
    public ChatRoom createChatRoom(String roomName) {
        if (!chatRooms.containsKey(roomName)) {
            ChatRoom chatRoom = new ChatRoom(roomName);
            chatRooms.put(roomName, chatRoom);
            return chatRoom;
        }
        return null;  // Chat room already exists
    }

    // Get a chat room
    public ChatRoom getChatRoom(String roomName) {
        return chatRooms.get(roomName);
    }
}
```

**2. Factory Pattern - `MessageFactory` Class**

The **Factory Pattern** is used to create instances of messages.

```java
// Factory Pattern to create different types of messages
class MessageFactory {

    public static Message createMessage(String sender, String receiver, String content) {
        return new Message(sender, receiver, content);
    }
}
```

**3. Observer Pattern - `User` Class (Observer)**

The **Observer Pattern** is used to notify users when a new message is received in the chat room.

```java
import java.util.ArrayList;
import java.util.List;

// Observer Pattern: User receives notifications of new messages
class User implements Observer {
    private String username;
    private List<ChatRoom> chatRooms;

    public User(String username) {
        this.username = username;
        this.chatRooms = new ArrayList<>();
    }

    public String getUsername() {
        return username;
    }

    // Subscribe user to a chat room
    public void joinChatRoom(ChatRoom chatRoom) {
        chatRoom.addObserver(this);
        chatRooms.add(chatRoom);
    }

    // Receive notification about new messages
    @Override
    public void update(String message) {
        System.out.println(username + " received message: " + message);
    }

    // Unsubscribe from a chat room
    public void leaveChatRoom(ChatRoom chatRoom) {
        chatRoom.removeObserver(this);
        chatRooms.remove(chatRoom);
    }
}
```

**4. Command Pattern - `MessageCommand` Class**

The **Command Pattern** is used to encapsulate the message sending action.

```java
// Command Pattern to send a message
interface Command {
    void execute();
}

class MessageCommand implements Command {
    private Message message;
    private ChatRoom chatRoom;

    public MessageCommand(ChatRoom chatRoom, Message message) {
        this.chatRoom = chatRoom;
        this.message = message;
    }

    @Override
    public void execute() {
        chatRoom.sendMessage(message);  // Send message to the chat room
    }
}
```

**5. Chat Room Class**

The `ChatRoom` class contains the logic for managing users and sending messages. This uses the **Observer Pattern** to notify all users when a message is sent.

```java
import java.util.ArrayList;
import java.util.List;

// Chat Room class to manage users and messages
class ChatRoom {
    private String roomName;
    private List<Observer> observers;
    private List<Message> messageHistory;

    public ChatRoom(String roomName) {
        this.roomName = roomName;
        this.observers = new ArrayList<>();
        this.messageHistory = new ArrayList<>();
    }

    public String getRoomName() {
        return roomName;
    }

    // Add observer (user)
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    // Remove observer (user)
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    // Send message to all users in the chat room
    public void sendMessage(Message message) {
        messageHistory.add(message);
        for (Observer observer : observers) {
            observer.update(message.getContent());  // Notify all users
        }
    }

    // Retrieve message history
    public List<Message> getMessageHistory() {
        return messageHistory;
    }
}
```

**6. Message Class**

The `Message` class holds the details of a message including the sender, receiver, content, and timestamp.

```java
import java.time.LocalDateTime;

// Message class representing a chat message
class Message {
    private String sender;
    private String receiver;
    private String content;
    private LocalDateTime timestamp;

    public Message(String sender, String receiver, String content) {
        this.sender = sender;
        this.receiver = receiver;
        this.content = content;
        this.timestamp = LocalDateTime.now();
    }

    public String getSender() {
        return sender;
    }

    public String getReceiver() {
        return receiver;
    }

    public String getContent() {
        return content;
    }

    public LocalDateTime getTimestamp() {
        return timestamp;
    }
}
```

**7. Observer Interface**

The `Observer` interface ensures that the `User` class can receive updates from the `ChatRoom`.

```java
// Observer interface for receiving notifications
interface Observer {
    void update(String message);
}
```

**8. Authentication and Secure Communication**

For user authentication, we can use a secure system based on usernames and passwords. For simplicity, here’s an example of the `AuthService` class that could handle user authentication.

```java
import java.util.HashMap;
import java.util.Map;

class AuthService {
    private static final Map<String, String> userCredentials = new HashMap<>();  // Simple in-memory credential storage

    static {
        // Example credentials
        userCredentials.put("user1", "password1");
        userCredentials.put("user2", "password2");
    }

    // Authenticate user
    public static boolean authenticate(String username, String password) {
        String storedPassword = userCredentials.get(username);
        return storedPassword != null && storedPassword.equals(password);
    }
}
```

***

#### **Testing the System**

Below is a simple example to test the chat system with two users, a chat room, and message sending/receiving.

```java
public class Main {
    public static void main(String[] args) {
        // Create instances of users
        User user1 = new User("user1");
        User user2 = new User("user2");

        // Create a chat room
        ChatRoomManager chatRoomManager = ChatRoomManager.getInstance();
        ChatRoom chatRoom = chatRoomManager.createChatRoom("Friends");

        // Users join the chat room
        user1.joinChatRoom(chatRoom);
        user2.joinChatRoom(chatRoom);

        // Send a message
        Message message = MessageFactory.createMessage("user1", "user2", "Hello, how are you?");
        Command messageCommand = new MessageCommand(chatRoom, message);
        messageCommand.execute();  // Send message

        // Receive message (via observer pattern)
        user2.update("Hello, how are you?");
        
        // User2 sends a reply
        Message reply = MessageFactory.createMessage("user2", "user1", "I'm good, thanks!");
        messageCommand = new MessageCommand(chatRoom, reply);
        messageCommand.execute();  // Send reply
        
        // User1 receives the reply
        user1.update("I'm good, thanks!");
    }
}
```

***

#### **Summary of Design Patterns Used**

1. **Singleton Pattern**: Used in the `ChatRoomManager` class to ensure a single instance that manages all chat rooms in the system.
2. **Factory Pattern**: Used in `MessageFactory` to create new `Message` objects.
3. **Observer Pattern**: Used to notify all subscribed users (observers) in a chat room when a new message is sent.
4. **Command Pattern**: Used to encapsulate message sending actions, allowing easy message execution.

#### **Conclusion**

This low-level design of a **chat application** uses **design patterns** to create a modular, scalable system that supports real-time messaging, secure user authentication, and efficient chat room management. The use of patterns like **Singleton**, **Factory**, **Observer**, and **Command** ensures a clean and maintainable architecture while allowing easy extensions like adding multimedia messages or integrating with external chat services.
