Sunday, March 23, 2014

Design an online chat server

Problem
Explain how you would design a chat server. In particular, provide details about the various backend components, classes, and methods. What would be the hardest problems to solve?
Solution

We certainly need a user class. We need to handle concurrency.
User class:
public class User {

    private Long userId;
    private String nickname;

    public User(Long userId, String nickname) {
     this.userId = userId;
     this.nickname = nickname;
    }

    public void setUserId(Long userId) {
     this.userId = userId;
    }

    public void setNickname(String nickname) {
     this.nickname = nickname;
    }

    public Long getUserId() {
     return userId;
    }

    public String getNickname() {
     return nickname;
    }

    public boolean equals(Object objectToCompare) {
     if (!(objectToCompare instanceof User)) {
      return false;
     }
     User incoming = (User) objectToCompare;
     if (incoming.getUserId() != null) {
      if (incoming.getUserId().equals(this.userId))
       return true;
     }
     return false;
    }
 
 public int hashCode(){//}
}


Also, we need a message class. Now a message should be associated with some user, also it should have timestamp associated as well. The benefit of timestamp is that user can see how recent the message is, also, we can delete the old messages from the server to free up the space.

Message :
public interface Message {
    public String getValue();
    public void setValue(String value);
 public TimeStamp getTimeStamp();
 public void setTimeStamp();
 public void getUser();
 public void setUser();
}

public class SimpleMessage implements Message {
    private String value;
 private String user;
 private TimeStamp timeStamp;
 
    public SimpleMessage() {
    }

    public SimpleMessage(String value) {
     this.value = value;
    }

    public String getValue() {
     return value;
    }

    public void setValue(String value) {
     this.value = value;
    }
 //other getters and setters as per message interface
}

Now we need session handling :
public class Session {
    Set users;
 
    public void handleEvent() {
        // hitting 'Enter' by any user
        // will trigger an event.
        // We need to handle them in turns
        // Need a queue here, perhaps
    }
 
    public void display(User user) {
        // display user's chat
    }
}

In the proper way (in java):
public interface ChatListener {
    public void notify(Message newMessage);
}

public class ChatWindow implements ChatListener {

    private User user;
    private List<Message> messageList;
    private Long id;

    public User getUser() {
     return user;
    }

    public List<Message> getMessageList() {
     return messageList;
    }

    public void setUser(User user) {
     this.user = user;
    }

    public void setMessageList(List<Message> messageList) {
     this.messageList = messageList;
    }

    public void addMessageToList(Message newMessage) {
     if (this.messageList == null) {
      this.messageList = new ArrayList<Message>();
     }
     this.messageList.add(newMessage);
    }

    public void notify(Message newMessage) {
     addMessageToList(newMessage);
    }

    public Long getId() {
     return id;
    }

    public void setId(Long id) {
     this.id = id;
    }
}

public class ChatSession {

    private List<ChatListener> registeredChatListeners;

    public void register(ChatWindow chatWindow) {
     if (registeredChatListeners == null)
      registeredChatListeners = new ArrayList<ChatListener>();
     registeredChatListeners.add(chatWindow);
    }

    public List<ChatListener> getRegisteredChatListeners() {
     return registeredChatListeners;
    }

    public void setRegisteredChatWindows(
      List<ChatListener> registeredChatListeners) {
     this.registeredChatListeners = registeredChatListeners;
    }

    public void incomingMessage(Long chatListenerId, Message message) {
     publish(message);
    }

    protected void publish(Message messageToPublish) {
     if (registeredChatListeners != null) {
      for (ChatListener eachListener : registeredChatListeners) {
       eachListener.notify(messageToPublish);
      }
     }
    }
}

Though we are using observer pattern here, but messaging systems like JMS are far more advanced and can handle very heavy loads.

Basically it allows you to define a common bus to which you can register and unregister participants, and also send messages that all of the participants will see. The big advantage over observer pattern is the very low coupling between the participants - you don't register with each object to get his messages - you just register once with the bus. In addition you get asynchronous processing - let's say you have 1000 chat sessions - if you use observer it means that for each message to complete it will take to update 1000 sessions. With message framework message send is very quick, and notifying all 1000 sessions is done in the background.

Reference - tian runhe,stackoverflow,

0 comments:

Post a Comment