/***************************************************************************************** Infosistema - OpenBaas Copyright(C) 2002-2014 Infosistema, S.A. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. www.infosistema.com info@openbaas.com Av. José Gomes Ferreira, 11 3rd floor, s.34 Miraflores 1495-139 Algés Portugal ****************************************************************************************/ package infosistema.openbaas.dataaccess.models; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Set; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import infosistema.openbaas.data.enums.ModelEnum; import infosistema.openbaas.data.models.ChatMessage; import infosistema.openbaas.data.models.ChatRoom; import infosistema.openbaas.utils.Const; import infosistema.openbaas.utils.Log; import infosistema.openbaas.utils.Utils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class ChatModel { // *** CONTRUCTORS *** // private ChatModel() { JedisPoolConfig poolConf = new JedisPoolConfig(); poolConf.setMaxActive(2); poolConf.setMaxWait(10000); pool = new JedisPool(poolConf, Const.getRedisChatServer(),Const.getRedisChatPort()); } private static ChatModel instance = null; public static ChatModel getInstance() { if (instance == null) instance = new ChatModel(); return instance; } // *** PRIVATE *** // private JedisPool pool; // *** CONSTANTS *** // private static final int MAXELEMS = 9999999; // *** KEYS *** // private static final String MESSAGE_KEY_FORMAT = "%s:%s"; private static final String CHATROOM_KEY_FORMAT = "%s:%s"; private static final String CHATROOM2_KEY_FORMAT = "%s_%s"; private static final String UNREAD_MSG_KEY_FORMAT = "%s_UnRead_%s"; private static final String PARTICIPANTS_KEY_FORMAT = "%s:%s"; private static final String USER_IN_PARTICIPANTS_LIST_1 = "%s:%s;*"; private static final String USER_IN_PARTICIPANTS_LIST_2 = "%s:*;%s;*"; private static final String USER_IN_PARTICIPANTS_LIST_3 = "%s:*;%s"; private String getMessageKey(String appId, String messageId) { return String.format(MESSAGE_KEY_FORMAT, appId, messageId); } private String getChatRoomKey(String appId, String roomId) { return String.format(CHATROOM_KEY_FORMAT, appId, roomId); } private String getChatRoomKey_2(String appId, String roomId) { return String.format(CHATROOM2_KEY_FORMAT, appId, roomId); } private String getUnreadMsgKey(String appId, String userId) { return String.format(UNREAD_MSG_KEY_FORMAT, appId, userId); } private String getParticipantsKey(String appId, String participants) { return String.format(PARTICIPANTS_KEY_FORMAT, appId, participants); } private List<String> getKeysForUserInParticipantsList(String appId, String userId) { List<String> retObj = new ArrayList<String>(); retObj.add(String.format(USER_IN_PARTICIPANTS_LIST_1, appId, userId)); retObj.add(String.format(USER_IN_PARTICIPANTS_LIST_2, appId, userId)); retObj.add(String.format(USER_IN_PARTICIPANTS_LIST_3, appId, userId)); return retObj; } // *** CREATE *** // public Boolean createChatRoom(String appId, String messageId,String roomId, String roomName, String roomCreator, Boolean flagNotification, String totalParticipants) { Boolean res = false; Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); if(flagNotification==null) flagNotification = false; Long milliseconds = new Date().getTime(); String[] participants = totalParticipants.split(Const.SEMICOLON); try { String roomKey = getChatRoomKey(appId, roomId); jedis.hset(roomKey, ChatRoom._ID, roomId); jedis.hset(roomKey, ChatRoom.ROOM_NAME, roomName); jedis.hset(roomKey, ChatRoom.ROOM_CREATOR, roomCreator); jedis.hset(roomKey, ChatRoom.FLAG_NOTIFICATION, flagNotification.toString()); jedis.hset(roomKey, ChatRoom.PARTICIPANTS, totalParticipants); jedis.hset(roomKey, ChatRoom.CREATEDDATE, milliseconds.toString()); jedis.rpush(getChatRoomKey_2(appId, roomId), messageId); if(participants.length==2) jedis.set(getParticipantsKey(appId, totalParticipants), roomId); res = true; } finally { pool.returnResource(jedis); } return res; } public Boolean createMessage(String appId, ChatMessage msg) { Boolean res = false; Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); long milliseconds = msg.getDate().getTime(); try { String msgKey = getMessageKey(appId, msg.get_id()); jedis.hset(msgKey, ChatMessage._ID, msg.get_id()); jedis.hset(msgKey, ChatMessage.SENDER, msg.getSender()); jedis.hset(msgKey, ChatMessage.DATE, String.valueOf(milliseconds)); try{jedis.hset(msgKey, ChatMessage.MESSAGE_TEXT, msg.getMessageText());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.FILE_ID, msg.getFileId());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.AUDIO_ID, msg.getAudioId());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.VIDEO_ID, msg.getVideoId());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.IMAGE_ID, msg.getImageId());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.HAS_FILE, msg.getHasFile());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.HAS_AUDIO, msg.getHasAudio());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.HAS_VIDEO, msg.getHasVideo());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.HAS_IMAGE, msg.getHasImage());}catch(Exception e){} try{jedis.hset(msgKey, ChatMessage.ROOM_ID, msg.getRoomId());}catch(Exception e){} res = true; } finally { pool.returnResource(jedis); } return res; } // *** UPDATE *** // public Boolean addMessage2Room(String appId, String messageId, String roomId, String senderId, List<String> unReadUsers) { Boolean res = false; Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); Iterator<String> it = unReadUsers.iterator(); try { jedis.rpush(getChatRoomKey_2(appId, roomId), messageId); while(it.hasNext()){ String user = it.next(); if (senderId == null || !senderId.equals(user)) jedis.rpush(getUnreadMsgKey(appId, user), messageId); } res = true; } finally { pool.returnResource(jedis); } return res; } public void updateMessageWithMedia(String appId, String messageId, ModelEnum type, String mediaId) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); long milliseconds = new Date().getTime(); try { String msgKey = getMessageKey(appId, messageId); jedis.hset(msgKey, ChatMessage.DATE, String.valueOf(milliseconds)); if(type.equals(ModelEnum.image)){ jedis.hset(msgKey, ChatMessage.IMAGE_ID, mediaId); } if(type.equals(ModelEnum.audio)){ jedis.hset(msgKey, ChatMessage.AUDIO_ID, mediaId); } if(type.equals(ModelEnum.video)){ jedis.hset(msgKey, ChatMessage.VIDEO_ID, mediaId); } if(type.equals(ModelEnum.storage)){ jedis.hset(msgKey, ChatMessage.FILE_ID, mediaId); } }catch(Exception e){ Log.error("", this, "updateMessageWithMedia", "Error updateMessageWithMedia redis.", e); }finally { pool.returnResource(jedis); } } // *** GET LIST *** // public List<String> getListParticipants(String appId, String roomId) { List<String> res = null; Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); try { String strParticipants = jedis.hget(getChatRoomKey(appId, roomId), ChatRoom.PARTICIPANTS); res = Utils.getListByString(strParticipants, ChatRoom.SEPARATOR); } finally { pool.returnResource(jedis); } return res; } public List<ChatMessage> getMessageList(String appId, String roomId, Date date, Integer numberMessages, String orientation) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); List<ChatMessage> res = new ArrayList<ChatMessage>(); if (orientation==null) orientation = ""; if (numberMessages==null) numberMessages = 10; try { String roomKey2 = getChatRoomKey_2(appId, roomId); Long size = jedis.llen(roomKey2); Integer endIndex = (int) (long) size; Integer startIndex = 1; int i = 0; int index = (int) (long)size; while(i<size){ index = ((int)(long) (size))-i-1; i++; Date dateCurr = new Date(); try { String messageIdCurr = jedis.lindex(roomKey2, index); long l = Long.valueOf(jedis.hget(getMessageKey(appId, messageIdCurr), ChatMessage.DATE)).longValue(); dateCurr = new Date(l); } catch (Exception e) {} if(dateCurr.compareTo(date)==0 && orientation.equals("front")){ index -= 1; break; } if(dateCurr.compareTo(date)==0 && !orientation.equals("front")){ //index += 1; break; } if(dateCurr.compareTo(date)<0) break; } if(orientation.equals("front")){ startIndex = index+1; if(index+numberMessages<endIndex) endIndex= index+numberMessages; }else{ endIndex = index; startIndex = index-numberMessages+1; if(startIndex<1) startIndex=1; } if(startIndex>endIndex){ return new ArrayList<ChatMessage>(); } for(int o=startIndex;o<=endIndex;o++){ String messageId = jedis.lindex(roomKey2, o); if(messageId!=null){ ChatMessage msg = new ChatMessage(); String msgKey = getMessageKey(appId, messageId); String sender = jedis.hget(msgKey, ChatMessage.SENDER); String messageText = jedis.hget(msgKey, ChatMessage.MESSAGE_TEXT); String fileId = jedis.hget(msgKey, ChatMessage.FILE_ID); String audioId = jedis.hget(msgKey, ChatMessage.AUDIO_ID); String videoId = jedis.hget(msgKey, ChatMessage.VIDEO_ID); String imageId = jedis.hget(msgKey, ChatMessage.IMAGE_ID); String hasFile = jedis.hget(msgKey, ChatMessage.HAS_FILE); String hasAudio = jedis.hget(msgKey, ChatMessage.HAS_AUDIO); String hasVideo = jedis.hget(msgKey, ChatMessage.HAS_VIDEO); String hasImage = jedis.hget(msgKey, ChatMessage.HAS_IMAGE); if(sender!=null) msg.setSender(sender); if(messageText!=null) msg.setMessageText(messageText); if(fileId!=null) msg.setFileId(fileId); if(audioId!=null) msg.setAudioId(audioId); if(videoId!=null) msg.setVideoId(videoId); if(imageId!=null) msg.setImageId(imageId); if(hasFile!=null) msg.setHasFile(hasFile); if(hasAudio!=null) msg.setHasAudio(hasAudio); if(hasVideo!=null) msg.setHasVideoId(hasVideo); if(hasImage!=null) msg.setHasImage(hasImage); String aux = jedis.hget(msgKey, ChatMessage.DATE); msg.setDate(new Date()); msg.setRoomId(roomId); try { long l = Long.valueOf(aux).longValue(); msg.setDate(new Date(l)); } catch (Exception e) { } msg.set_id(messageId); res.add(msg); } } }catch(Exception e){ Log.error("", this, "getMessageList", "Error getMessageList redis.", e); } finally { pool.returnResource(jedis); } return res; } public List<String> getMessageChatroom(String appId, String roomId) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); List<String> res = new ArrayList<String>(); try { res = jedis.lrange(getChatRoomKey_2(appId, roomId), 0, MAXELEMS); } catch (Exception e) { Log.error("", this, "getMessageChatroom", "Error getMessageChatroom redis."+ res.size(), e); }finally { pool.returnResource(jedis); } return res; } // *** GET *** // public ChatRoom getChatRoom(String appId, String roomId) { ChatRoom res = new ChatRoom(); Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); try { String roomKey = getChatRoomKey(appId, roomId); res.set_id(roomId); res.setRoomName(jedis.hget(roomKey, ChatRoom.ROOM_NAME)); res.setRoomCreator(jedis.hget(roomKey, ChatRoom.ROOM_CREATOR)); res.setFlagNotification(Boolean.parseBoolean(jedis.hget(roomKey, ChatRoom.FLAG_NOTIFICATION))); res.setParticipants(jedis.hget(roomKey, ChatRoom.PARTICIPANTS).split(Const.SEMICOLON)); res.setCreatedDate(new Date()); try { long l = Long.valueOf(jedis.hget(roomKey, ChatRoom.CREATEDDATE)).longValue(); res.setCreatedDate(new Date(l)); } catch (Exception e) {} } finally { pool.returnResource(jedis); } return res; } public ChatMessage getMessage(String appId, String messageId) { ChatMessage res = new ChatMessage(); Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); try { String msgKey = getMessageKey(appId, messageId); String sender = jedis.hget(msgKey, ChatMessage.SENDER); String messageText = jedis.hget(msgKey, ChatMessage.MESSAGE_TEXT); String fileId = jedis.hget(msgKey, ChatMessage.FILE_ID); String audioId = jedis.hget(msgKey, ChatMessage.AUDIO_ID); String videoId = jedis.hget(msgKey, ChatMessage.VIDEO_ID); String imageId = jedis.hget(msgKey, ChatMessage.IMAGE_ID); String hasFile = jedis.hget(msgKey, ChatMessage.HAS_FILE); String hasAudio = jedis.hget(msgKey, ChatMessage.HAS_AUDIO); String hasVideo = jedis.hget(msgKey, ChatMessage.HAS_VIDEO); String hasImage = jedis.hget(msgKey, ChatMessage.HAS_IMAGE); String roomId = jedis.hget(msgKey, ChatMessage.ROOM_ID); if(sender!=null) res.setSender(sender); if(messageText!=null) res.setMessageText(messageText); if(fileId!=null) res.setFileId(fileId); if(audioId!=null) res.setAudioId(audioId); if(videoId!=null) res.setVideoId(videoId); if(imageId!=null) res.setImageId(imageId); if(hasFile!=null) res.setHasFile(hasFile); if(hasAudio!=null) res.setHasAudio(hasAudio); if(hasVideo!=null) res.setHasVideoId(hasVideo); if(hasImage!=null) res.setHasImage(hasImage); if(roomId!=null) res.setRoomId(roomId); res.setDate(new Date()); try { long l = Long.valueOf(jedis.hget(msgKey, ChatMessage.DATE)).longValue(); res.setDate(new Date(l)); } catch (Exception e) {} res.set_id(messageId); } finally { pool.returnResource(jedis); } return res; } public int readMessages(String appId, String userId, JSONArray jsonArray) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); int res = 0; Long aux = (long) 0; try { if(jsonArray.length()>0){ String unreadMsgKey = getUnreadMsgKey(appId, userId); for(int i = 0;i<jsonArray.length();i++){ aux = jedis.lrem(unreadMsgKey, 0, jsonArray.getString(i)); res += ((int)(long)aux); } } } catch (JSONException e) { Log.error("", this, "readMessages", "Error readMessages redis.", e); } finally { pool.returnResource(jedis); } return res; } public List<String> getTotalUnreadMsg(String appId, String userId) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); List<String> res = new ArrayList<String>(); try { res = jedis.lrange(getUnreadMsgKey(appId, userId), 0, MAXELEMS); } catch (Exception e) { Log.error("", this, "getTotalListElements", "Error getTotalListElements redis."+ res.size(), e); }finally { pool.returnResource(jedis); } return res; } public List<String> getAllUserChats(String appId, String userId) { List<String> res = new ArrayList<String>(); List<String> kList = getKeysForUserInParticipantsList(appId, userId); Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); try { for (String k : kList) { Set<String> keys = jedis.keys(k); Iterator<String> i = keys.iterator(); while (i.hasNext()) { String s = jedis.get(i.next()); if (!res.contains(s)) res.add(s); } } }catch(Exception e){ Log.error("", this, "getMessageList", "Error getMessageList redis.", e); } finally { pool.returnResource(jedis); } return res; } // *** EXISTS *** // public String existsChat(String participants, String appId) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); String res=null; try { res = jedis.get(getParticipantsKey(appId, participants)); }catch(Exception e){ Log.error("", this, "getMessageList", "Error getMessageList redis.", e); } finally { pool.returnResource(jedis); } return res; } public Boolean existsKey(String appId, String key) { Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); Boolean res = false; try { res = jedis.exists(getMessageKey(appId, key)); } catch (Exception e) { Log.error("", this, "existsKey", "Error existsKey redis: "+ getMessageKey(appId, key), e); }finally { pool.returnResource(jedis); } return res; } public Boolean hasNotification(String appId, String roomId) { Boolean res = false; Jedis jedis = pool.getResource(); jedis.auth(Const.getRedisChatPass()); try { res = (Boolean.parseBoolean(jedis.hget(getChatRoomKey(appId, roomId), ChatRoom.FLAG_NOTIFICATION))); } finally { pool.returnResource(jedis); } return res; } }