/src/java/com/fw/lw/websocket/WebRTCRoomBean.java
Java | 506 lines | 241 code | 45 blank | 220 comment | 95 complexity | 612d1284526180de32f5eba02ec84614 MD5 | raw file
- package com.fw.lw.websocket;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.Map;
- import java.util.Queue;
- import javax.json.Json;
- import javax.json.JsonObject;
- import javax.websocket.Session;
- import org.apache.log4j.Logger;
- /**
- *
- * @author fasiha.anjum
- */
- public class WebRTCRoomBean {
-
- private static final Logger LOG = Logger.getLogger(WebRTCRoomBean.class);
- /**
- * The INSTANCE bean
- */
- private static final WebRTCRoomBean INSTANCE = new WebRTCRoomBean();
- /**
- * Private class that represents a room member. A member is the username,
- * the session (web socket) and a queue of un delivered messages for the user
- * (messages to send as soon as he joins).
- */
- private class RoomMember {
- /**
- * username
- */
- private String username;
- /**
- * session
- */
- private Session session;
- /**
- * undelivered messages for this user
- */
- private Queue<JsonObject> undeliveredMessages;
- /**
- * Empty constructor
- */
- public RoomMember() {
- undeliveredMessages = new LinkedList<>();
- }
- /**
- * Getter for username
- *
- * @return the username
- */
- public String getUsername() {
- return username;
- }
- /**
- * Setter for username
- *
- * @param username the new username
- */
- public void setUsername(String username) {
- this.username = username;
- }
- /**
- * Getter for the session
- *
- * @return the session
- */
- public Session getSession() {
- return session;
- }
- /**
- * Setter for the session
- *
- * @param session the new session
- */
- public void setSession(Session session) {
- this.session = session;
- }
- /**
- * Getter for the queue of undelivered messages
- *
- * @return The queue
- */
- public Queue<JsonObject> getUndeliveredMessages() {
- return undeliveredMessages;
- }
- /**
- * String representation
- *
- * @return
- */
- @Override
- public String toString() {
- return new StringBuilder()
- .append(getUsername())
- .append("(")
- .append((getSession() == null) ? "null" : getSession().getId())
- .append(")")
- .toString();
- }
- }
- /**
- * Private class that represents a room. A room is composed by two members
- * and the room key. The members are always created (they are never null,
- * but the username or session can be null).
- */
- private class Room {
- /**
- * The room key
- */
- private String key;
- /**
- * First member
- */
- private RoomMember member1;
- /**
- * Second member
- */
- private RoomMember member2;
- /**
- * Constructor using the key.
- *
- * @param key The room key
- */
- public Room(String key) {
- this.key = key;
- member1 = new RoomMember();
- member2 = new RoomMember();
- }
- /**
- * Getter for the key
- *
- * @return the key
- */
- public String getKey() {
- return key;
- }
- /**
- * Getter for user member 1
- *
- * @return the member1
- */
- public RoomMember getMember1() {
- return member1;
- }
- /**
- * Getter for member 2
- *
- * @return the member 2
- */
- public RoomMember getMember2() {
- return member2;
- }
- /**
- * A new member is joined to the room. The username and session is
- * filled and the un delivered messages are sent (if there were any).
- *
- * @param username The username which is joining
- * @param session The session which is joining
- */
- public void addMember(String userName, Session session) {
- if (userName != null && session != null) {
- if (!userName.equals(member1.getUsername()) && !userName.equals(member2.getUsername())) {
- if (member1.getUsername() == null) {
- this.member1.setUsername(userName);
- this.member1.setSession(session);
- // process undelivered messages
- while (!member1.getUndeliveredMessages().isEmpty()) {
- LOG.info("Sending undelivered messages for username=" + member1.getUsername());
- WebRTCEndPoint.send(member1.getSession(), member1.getUndeliveredMessages().poll());
- }
- } else if (member2.getUsername() == null) {
- this.member2.setUsername(userName);
- this.member2.setSession(session);
- // process undelivered messages
- while (!member2.getUndeliveredMessages().isEmpty()) {
- LOG.info("Sending undelivered messages for username=" + member2.getUsername());
- WebRTCEndPoint.send(member2.getSession(), member2.getUndeliveredMessages().poll());
- }
- }
- }
- }
- }
- /**
- * Return the member for this session or null
- *
- * @param session The session to search the member
- * @return The member with this session or null
- */
- public RoomMember getMember(Session session) {
- if (session != null) {
- if (member1.getSession() != null
- && session.getId().equals(member1.getSession().getId())) {
- return member1;
- } else if (member2.getSession() != null
- && session.getId().equals(member2.getSession().getId())) {
- return member2;
- }
- }
- return null;
- }
- /**
- * return the member for this username or null.
- *
- * @param username The username to search the member
- * @return The member for this username or null
- */
- public RoomMember getMember(String userName) {
- if (userName != null) {
- if (userName.equals(member1.getUsername())) {
- return member1;
- } else if (userName.equals(member2.getUsername())) {
- return member2;
- }
- }
- return null;
- }
- /**
- * return the other member, the one which is not the parameter.
- *
- * @param sesstion The session of the user
- * @return The member or null (the member can be null / empty)
- */
- public RoomMember getOtherMember(Session session) {
- if (session != null) {
- if (member1.getSession() != null
- && session.getId().equals(member1.getSession().getId())) {
- return member2;
- } else if (member2.getSession() != null
- && session.getId().equals(member2.getSession().getId())) {
- return member1;
- }
- }
- return null;
- }
- /**
- * return the other member, the one which is not the parameter.
- *
- * @param username The username to search the counterpart
- * @return The member or null (the member can be null / empty)
- */
- public RoomMember getOtherMember(String userName) {
- if (userName != null) {
- if (userName.equals(member1.getUsername())) {
- return member2;
- } else if (userName.equals(member2.getUsername())) {
- return member1;
- }
- }
- return null;
- }
- /**
- * Remove the member from the room. The session is closed if it exists.
- *
- * @param username The username to remove from the room
- */
- public void removeMember(String userName) {
- if (userName != null) {
- if (userName.equals(member1.getUsername())) {
- member1.setUsername(null);
- WebRTCEndPoint.closeSession(member1.getSession());
- member1.setSession(null);
- member1.getUndeliveredMessages().clear();
- } else if (userName.equals(member2.getUsername())) {
- member2.setUsername(null);
- WebRTCEndPoint.closeSession(member2.getSession());
- member2.setSession(null);
- member2.getUndeliveredMessages().clear();
- }
- }
- }
- /**
- * Check if the room is full (both members are in the room).
- *
- * @return true if the two members are filled
- */
- public boolean isFull() {
- return member1.getUsername() != null && member2.getUsername() != null;
- }
- /**
- * Check if the room is empty (both members are null)
- *
- * @return true if the two members are null
- */
- public boolean isEmpty() {
- return member1.getUsername() == null && member2.getUsername() == null;
- }
- /**
- * Check if in this room there is one user which is waiting and it is
- * not the parameter username.
- *
- * @param username the username which is asking
- * @return true if there is one username waiting in this room
- */
- public boolean isTheOtherMemberWaiting(String userName) {
- if (userName != null) {
- return ((member1.getUsername() != null && !userName.equals(member1.getUsername()))
- || (member2.getUsername() != null && !userName.equals(member2.getUsername())))
- && !isFull();
- }
- return false;
- }
- /**
- * Debug representation.
- *
- * @return
- */
- @Override
- public String toString() {
- return new StringBuilder()
- .append(key)
- .append(" -> ")
- .append(getMember1().toString())
- .append("-")
- .append(getMember2().toString())
- .toString();
- }
- }
- /**
- * rooms indexed by room key
- */
- private Map<String, Room> roomsByKey;
- /**
- * rooms indexed by session id
- */
- private Map<String, Room> roomsBySession;
- /**
- * Private constructor.
- */
- private WebRTCRoomBean() {
- this.roomsByKey = new HashMap<>();
- this.roomsBySession = new HashMap<>();
- }
- /**
- * The INSTANCE method. TODO: A EJB is not injected in the WebSocket
- * endpoint.
- *
- * @return The room bean INSTANCE
- */
- static public WebRTCRoomBean getRoomBean() {
- return INSTANCE;
- }
- /**
- * It checks if in the specified room there is one user waiting.
- *
- * @param roomKey The room to search
- * @param userName The user asking for the other user
- * @return true if in that room there is another user waiting
- */
- synchronized public boolean isTheOtherMemberWaiting(String roomKey, String userName) {
- Room room = roomsByKey.get(roomKey);
- return room != null && room.isTheOtherMemberWaiting(userName);
- }
- /**
- * It returns if a specific room is full.
- *
- * @param roomKey The room to check
- * @return true if it is full, false otherwise
- */
- synchronized public boolean isTheRoomFull(String roomKey) {
- Room room = roomsByKey.get(roomKey);
- return room != null && room.isFull();
- }
- /**
- * A user is connecting to a room. The room is created if it didn't exist
- * and the user is added to that room. If the room already existed the user
- * is added to that room.
- *
- * @param roomKey The room key
- * @param userName The username which is joining
- * @param session The session (websocket) of the user
- */
- synchronized public void connect(String roomKey, String userName, Session session) {
- Room room = roomsByKey.get(roomKey);
- if (room == null) {
- // new room => create and assign user 1
- room = new Room(roomKey);
- room.addMember(userName, session);
- roomsByKey.put(roomKey, room);
- roomsBySession.put(session.getId(), room);
- } else if (!room.isFull()) {
- room.addMember(userName, session);
- roomsBySession.put(session.getId(), room);
- }
- }
- /**
- * The user disconnects from the room using the session id. The room is
- * located and the user removed from that room.
- *
- * @param session The session of the user
- */
- synchronized public void disconnect(Session session) {
- Room room = roomsBySession.get(session.getId());
- if (room != null) {
- RoomMember member = room.getMember(session);
- if (member != null) {
- disconnect(room, member);
- }
- }
- }
- /**
- * The user disconnects from the room using the username. The room is
- * located and the user removed from that room.
- *
- * @param roomKey The roomKey of the user
- * @param userName The username
- */
- synchronized public void disconnect(String roomKey, String userName) {
- Room room = roomsByKey.get(roomKey);
- if (room != null) {
- RoomMember member = room.getMember(userName);
- if (member != null) {
- disconnect(room, member);
- }
- }
- }
- /**
- * The user is removed from the session. If there is a partner in the room a
- * "bye" message is sent to him in order to close the conversation (it is
- * done in the hangup).
- *
- * @param room The room with the user which is disconnecting
- * @param member The user member
- */
- private void disconnect(Room room, RoomMember member) {
- if (room != null && member != null) {
- RoomMember otherMember = room.getOtherMember(member.getUsername());
- // remove the index by the session id
- roomsBySession.remove(member.getSession().getId());
- // remove the member
- room.removeMember(member.getUsername());
- if (otherMember == null || otherMember.getUsername() == null) {
- // the room is empty => delete completely
- roomsByKey.remove(room.getKey());
- } else {
- // send "bye" to the other member
- JsonObject bye = Json.createObjectBuilder().add("type", "bye").build();
- WebRTCEndPoint.send(otherMember.getSession(), bye);
- }
- }
- }
- /**
- * Method that sends a message to the partner member of a room. The room is
- * located and the message is sent to the the other partner.
- *
- * @param session The session of the user
- * @param data The data to send
- */
- synchronized public void sendToTheOther(Session session, JsonObject data) {
- Room room = roomsBySession.get(session.getId());
- if (room != null) {
- RoomMember otherMember = room.getOtherMember(session);
- if (otherMember != null && otherMember.getSession() != null) {
- // the other user is connected
- LOG.info("Sending message to username=" + otherMember.getUsername());
- WebRTCEndPoint.send(otherMember.getSession(), data);
- } else if (otherMember != null) {
- // the other user is not connected => add the offer
- LOG.info("Saving message to username=" + otherMember.getUsername());
- otherMember.getUndeliveredMessages().add(data);
- }
- }
- }
- }