/***************************************************************************************** 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.comunication.bound; import infosistema.openbaas.comunication.connector.IConnector; import infosistema.openbaas.comunication.message.Message; import infosistema.openbaas.data.Metadata; import infosistema.openbaas.data.Result; import infosistema.openbaas.data.enums.ModelEnum; import infosistema.openbaas.data.models.ChatMessage; import infosistema.openbaas.data.models.ChatRoom; import infosistema.openbaas.data.models.Media; import infosistema.openbaas.middleLayer.ChatMiddleLayer; import infosistema.openbaas.middleLayer.MediaMiddleLayer; import infosistema.openbaas.middleLayer.NotificationMiddleLayer; import infosistema.openbaas.middleLayer.SessionMiddleLayer; import infosistema.openbaas.utils.Log; import infosistema.openbaas.utils.Utils; import org.apache.commons.codec.binary.Base64; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import com.sun.jersey.core.header.FormDataContentDisposition; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Hashtable; public class Outbound { private String userId; private IConnector connector; private static ArrayList<Outbound> msgOutboundList = new ArrayList<Outbound>(); private static Hashtable<String, Outbound> userOutbound = new Hashtable<String, Outbound>(); private SessionMiddleLayer sessionMid = SessionMiddleLayer.getInstance(); private ChatMiddleLayer chatMid = ChatMiddleLayer.getInstance(); private MediaMiddleLayer mediaMid = MediaMiddleLayer.getInstance(); private NotificationMiddleLayer noteMid = NotificationMiddleLayer.getInstance(); public Outbound(IConnector connector) { this.connector = connector; } public static void setUserOutbound(String userId, Outbound outbound) { userOutbound.put(userId, outbound); } public static void removeUserOutbound(String userId) { userOutbound.remove(userId); } public static Outbound getUserOutbound(String userId) { return userOutbound.get(userId); } public String getUserId() { return this.userId; } public void setUserId(String userId) { this.userId = userId; } /*** RECEIVE MESSAGES ***/ public void processMessage(String message) { String msgType = null; String appId = null; String sessionToken = null; String messageId = null; JSONObject data = null; try { JSONObject msg = new JSONObject(message); try { msgType = msg.getString(Message.TYPE); } catch (Exception e) {} try { appId = msg.getString(Message.APP_ID); } catch (Exception e) {} try { sessionToken = msg.getString(Message.SESSION_TOKEN); } catch (Exception e) {} try { messageId = msg.getString(Message.MESSAGE_ID); } catch (Exception e) {} try { data = msg.getJSONObject(Message.DATA); } catch (Exception e) {} if (!sessionMid.checkAppForToken(sessionToken, appId)) { sendNOKMessage(appId, messageId, "Invalid sessionToken!"); return; } JSONObject retData = null; if (msgType == null) { sendNOKMessage(appId, messageId, "Type message can't be empty!"); } else if (msgType.equals(Message.AUTHENTICATE)) { retData = processMsgAuthenticate(appId, messageId, sessionToken); } else if (msgType.equals(Message.OK)) { //processMsgOk(data); } else if (msgType.equals(Message.NOK)) { //processMsgNok(data); } else if (msgType.equals(Message.CREATE_CHAT_ROOM)) { retData = processMsgCreateChatRoom(data, appId, messageId, sessionToken); } else if (msgType.equals(Message.SENT_CHAT_MSG)) { retData = processMsgSentChatMsg(data, messageId, appId, sessionToken); } else if (msgType.equals(Message.PING)) { retData = processMsgPing(appId, messageId); } else if (msgType.equals(Message.PONG)) { retData = processMsgPong(); } else { sendNOKMessage(appId, messageId, "Invalid message type: " + msgType + "!"); } if (retData != null) { if (retData.has(Message.ERROR_MESSAGE)) { sendNOKMessage(appId, messageId, retData.getString(Message.ERROR_MESSAGE)); } else { sendOKMessage(appId, messageId, retData); } } } catch (JSONException e) { Log.error("", this, "processMessage", "Error processing message", e); } } private JSONObject processMsgAuthenticate(String appId, String messageId, String sessionToken) { try { String userId = sessionMid.getUserIdUsingSessionToken(sessionToken); setUserId(userId); Outbound.removeOutbound(this); Outbound.setUserOutbound(userId, this); return new JSONObject(); } catch (Exception e) { Log.error("", this, "processMsgAuthenticate", "Error processing message!", e); return getErrorJSONObject(appId, messageId, "Error processing message!"); } } private JSONObject processMsgCreateChatRoom(JSONObject data, String appId, String messageId, String sessionToken) { String roomName = null; boolean flag=false; JSONArray participants=null; Boolean flagNotification=false; String userId = sessionMid.getUserIdUsingSessionToken(sessionToken); try { try { roomName = data.getString(ChatRoom.ROOM_NAME); } catch (Exception e) {} try { participants = data.getJSONArray(ChatRoom.PARTICIPANTS); } catch (Exception e) { Log.error("", this, "processMsgCreateChatRoom", "Error creating chat.", e); } try { flagNotification = data.optBoolean(ChatRoom.FLAG_NOTIFICATION); } catch (Exception e) { Log.error("", this, "processMsgCreateChatRoom", "Error creating chat.", e); } for(int i = 0; i < participants.length(); i++){ String userCurr = participants.getString(i); if(userCurr.equals(userId)) flag = true; } if(!flag) participants.put(userId); if (roomName==null) { roomName = Utils.getStringByJSONArray(participants, ";"); } ChatRoom chatRoom = chatMid.createChatRoom(appId, roomName, userId, flagNotification, participants); return chatRoom.serialize(); } catch (Exception e) { Log.error("", this, "processMsgCreateChatRoom", "Error creating chat.", e); return getErrorJSONObject(appId, messageId, "Error creating chat!"); } } private JSONObject processMsgSentChatMsg(JSONObject data, String messageId, String appId, String sessionToken) { String message = null; String roomId = null; try { message = data.getString(Message.TEXT); } catch (JSONException e) { } try { roomId = data.getString(Message.CHAT_ROOM_ID); } catch (JSONException e) { Log.error("", this, "processMsgRecvChatMsg", "Error getting data",e); } String messageText = null; String fileId = null; String imageId = null; String audioId = null; String videoId = null; String hasFile = null; String hasImage = null; String hasAudio = null; String hasVideo = null; try { hasFile = data.getString(Message.HAS_FILE); } catch (JSONException e1) { } try { hasImage = data.getString(Message.HAS_IMAGE); } catch (JSONException e1) { } try { hasAudio = data.getString(Message.HAS_AUDIO); } catch (JSONException e1) { } try { hasVideo = data.getString(Message.HAS_VIDEO); } catch (JSONException e1) { } ModelEnum flag = null; String userId = sessionMid.getUserIdUsingSessionToken(sessionToken); if (message != null){ try { messageText = URLDecoder.decode(message, "UTF-8"); } catch (UnsupportedEncodingException e) { Log.error("", this, "processMsgRecvChatMsg", "Error in decoding message.", e); return getErrorJSONObject(appId, messageId, "Error in decoding message."); } } if (chatMid.existsChatRoom(appId, roomId)) { try { InputStream imageInputStream = null; InputStream videoInputStream = null; InputStream audioInputStream = null; InputStream fileInputStream = null; String stmp = null; try { stmp = data.getString(Message.IMAGE); if (stmp != null) imageInputStream = convertBase64(stmp); } catch (Exception e) {} try { stmp = null; stmp = data.getString(Message.VIDEO); if (stmp != null) videoInputStream = convertBase64(stmp); } catch (Exception e) {} try { stmp = null; stmp = data.getString(Message.AUDIO); if (stmp != null) audioInputStream = convertBase64(stmp); } catch (Exception e) {} try { stmp = null; stmp = data.getString(Message.FILE); if (stmp != null) fileInputStream = convertBase64(stmp); } catch (Exception e) {} FormDataContentDisposition fileDetail = FormDataContentDisposition.name("media").fileName("media.txt").build(); Result res = null; if (imageInputStream != null && fileDetail!=null) { fileDetail = FormDataContentDisposition.name("media").fileName("image.png").build(); res = mediaMid.createMedia(imageInputStream, fileDetail, appId, userId, ModelEnum.image, null, Metadata.getNewMetadata(null), null); flag = ModelEnum.image; } else if (videoInputStream!=null && fileDetail!=null) { fileDetail = FormDataContentDisposition.name("media").fileName("video.wmv").build(); res = mediaMid.createMedia(videoInputStream, fileDetail, appId, userId, ModelEnum.video, null, Metadata.getNewMetadata(null), null); flag = ModelEnum.video; } else if (audioInputStream!=null && fileDetail!=null) { fileDetail = FormDataContentDisposition.name("media").fileName("audio.mp3").build(); res = mediaMid.createMedia(audioInputStream, fileDetail, appId, userId, ModelEnum.audio, null, Metadata.getNewMetadata(null), null); flag = ModelEnum.audio; } else if (fileInputStream!=null && fileDetail!=null) { res = mediaMid.createMedia(fileInputStream, fileDetail, appId, userId, ModelEnum.storage, null, Metadata.getNewMetadata(null), null); flag = ModelEnum.storage; } if (res!=null && flag!=null) { String fid = ((Media)res.getData()).get_id(); if (flag.equals(ModelEnum.image)) { imageId = fid; hasImage = "true"; } if (flag.equals(ModelEnum.storage)) { fileId = fid; hasFile = "true"; } if (flag.equals(ModelEnum.audio)) { audioId = fid; hasAudio = "true"; } if (flag.equals(ModelEnum.video)) { videoId = fid; hasVideo = "true"; } } ChatMessage msg = chatMid.sendMessage(appId, userId, roomId, messageText, fileId, imageId, audioId, videoId, hasFile, hasImage, hasAudio, hasVideo); if (msg != null) { noteMid.setPushNotificationsTODO(appId, userId, roomId); return msg.serialize(); }else{ return getErrorJSONObject(appId, messageId, "Error sendMessage"); } } catch (Exception e) { Log.error("", this, "sendMessage", "Error sendMessage.", e); return getErrorJSONObject(appId, messageId, "Error sendMessage"); } }else{ return getErrorJSONObject(appId, messageId, "Chat Room not found"); } } private JSONObject processMsgPing(String appId, String messageId) { sendPongMessage(appId, messageId); return null; } private JSONObject processMsgPong() { return null; } private JSONObject getErrorJSONObject(String appId, String messageId, String errorMessage) { JSONObject obj = new JSONObject(); try { obj.put(Message.ERROR_MESSAGE, errorMessage); } catch (JSONException e1) { obj = null; sendNOKMessage(appId, messageId, errorMessage); Log.error("", this, "processMsgCreateChatRoom", "Error processing error message", e1); } return obj; } /*** SEND MESSAGES ***/ public boolean sendPingMessage(String appId) { Message message = new Message(Message.PING, appId); return sendMessage(message); } public boolean sendPongMessage(String appId, String messageId) { Message message = new Message(Message.PONG, appId, messageId); return sendMessage(message); } public boolean sendOKMessage(String appId, String messageId, JSONObject data) { if (messageId == null) return true; Message message = new Message(Message.OK, appId, messageId); if (data != null) message.setData(data); return sendMessage(message); } public boolean sendNOKMessage(String appId, String messageId, String errorMessage) { if (messageId == null) return true; Message message = new Message(Message.NOK, appId, messageId); try { JSONObject data = new JSONObject (); data.put(Message.ERROR_MESSAGE, errorMessage); message.setData(data); } catch (JSONException e) { Log.error("", this, "sendNOKMessage", "Erro sending NOK message"); return false; } return sendMessage(message); } public boolean sendRecvMessage(String appId, String roomId, ChatMessage msg, String userId) { Message message = new Message(Message.RECV_CHAT_MSG, appId); try { JSONObject data = new JSONObject (); data.put(Message.MESSAGE, msg.serialize()); ChatRoom room = chatMid.getChatRoom(appId, roomId); int unReadMsgNumber = chatMid.getUnreadMsgs(appId, userId, roomId).size(); room.setUnreadMessages(unReadMsgNumber); data.put(Message.MESSAGE, msg.serialize()); data.put(Message.CHAT_ROOM, room.serialize()); message.setData(data); } catch (JSONException e) { Log.error("", this, "sendRecvMessage", "Erro sending Recv message"); return false; } return sendMessage(message); } public boolean sendMessage(Message message) { return connector.sendMessage(message); } /*** OTHERS ***/ public static void addOutbound(Outbound out) { msgOutboundList.add(out); } public static void removeOutbound(Outbound out) { msgOutboundList.remove(out); } private InputStream convertBase64(String str) { byte[] ba = Base64.decodeBase64(str); ByteArrayInputStream res = new ByteArrayInputStream(ba); return res; } }