/** * Creates a new {@link IOAcknowledge} instance which sends its arguments back to the server. * * @param message the message * @return an {@link IOAcknowledge} instance, may be <code>null</code> if server doesn't request * one. */ private IOAcknowledge remoteAcknowledge(IOMessage message) { String _id = message.getId(); if (_id.equals("")) { return null; } else if (!_id.endsWith("+")) { _id = _id + "+"; } final String id = _id; final String endPoint = message.getEndpoint(); return new IOAcknowledge() { @Override public void ack(Object... args) { String jsonString = null; try { jsonString = objectMapper.writeValueAsString(args); } catch (Exception e) { error( new SocketIOException( "You can only put values in IOAcknowledge.ack() which can be serialized", e)); } IOMessage ackMsg = new IOMessage(IOMessage.TYPE_ACK, endPoint, id + jsonString); sendPlain(ackMsg.toString()); } }; }
/** * finds the corresponding callback object to an incoming message. Returns a dummy callback if no * corresponding callback can be found * * @param message the message * @return the iO callback * @throws SocketIOException */ private IOCallback findCallback(IOMessage message) throws SocketIOException { if ("".equals(message.getEndpoint())) { return this; } SocketIO socket = sockets.get(message.getEndpoint()); if (socket == null) { throw new SocketIOException("Cannot find socket for '" + message.getEndpoint() + "'"); } return socket.getCallback(); }
/** * Connects a socket to the IOConnection. * * @param socket the socket to be connected * @return true, if successfully registered on this transport, otherwise false. */ public boolean register(SocketIO socket) { String namespace = socket.getNamespace(); if (sockets.containsKey(namespace)) { return false; } sockets.put(namespace, socket); socket.setHeaders(headers); IOMessage connect = new IOMessage(IOMessage.TYPE_CONNECT, socket.getNamespace(), ""); sendPlain(connect.toString()); return true; }
/** * adds an {@link IOAcknowledge} to an {@link IOMessage}. * * @param message the {@link IOMessage} * @param ack the {@link IOAcknowledge} */ private void synthesizeAck(IOMessage message, IOAcknowledge ack) { if (ack != null) { int id = nextId++; acknowledge.put(id, ack); message.setId(id + "+"); } }
/** * emits an event from {@link SocketIO} to the {@link IOTransport}. * * @param socket the socket * @param event the event * @param ack acknowledge package which can be called from the server * @param args the arguments to be send */ public void emit(SocketIO socket, String event, IOAcknowledge ack, Object... args) { String jsonString = null; try { Map<String, Object> map = new HashMap<String, Object>(); map.put("name", event); map.put("args", args); jsonString = objectMapper.writeValueAsString(map); IOMessage message = new IOMessage(IOMessage.TYPE_EVENT, socket.getNamespace(), jsonString); synthesizeAck(message, ack); sendPlain(message.toString()); } catch (Exception e) { error( new SocketIOException( "Error while emitting an event. Make sure you only try to send arguments, which can be serialized into JSON.")); } }
private void send(String content) throws IOException, JSONException { IOMessage msg = new IOMessage(IOMessage.MESSAGE, -1, "", content); socket.getWebSocket().send(msg.toString()); }
/** * sends a String message from {@link SocketIO} to the {@link IOTransport}. * * @param socket the socket * @param ack acknowledge package which can be called from the server * @param text the text */ public void send(SocketIO socket, IOAcknowledge ack, String text) { IOMessage message = new IOMessage(IOMessage.TYPE_MESSAGE, socket.getNamespace(), text); synthesizeAck(message, ack); sendPlain(message.toString()); }
/** * Transport message. {@link IOTransport} calls this, when a message has been received. * * @param text the text */ public void transportMessage(String text) { log.debug("< " + text); IOMessage message; try { message = new IOMessage(text); } catch (Exception e) { error(new SocketIOException("Garbage from server: " + text, e)); return; } resetTimeout(); switch (message.getType()) { case IOMessage.TYPE_DISCONNECT: try { findCallback(message).onDisconnect(); } catch (Exception e) { error(new SocketIOException("Exception was thrown in onDisconnect()", e)); } break; case IOMessage.TYPE_CONNECT: try { if (firstSocket != null && "".equals(message.getEndpoint())) { if (firstSocket.getNamespace().equals("")) { firstSocket.getCallback().onConnect(); } else { IOMessage connect = new IOMessage(IOMessage.TYPE_CONNECT, firstSocket.getNamespace(), ""); sendPlain(connect.toString()); } } else { findCallback(message).onConnect(); } firstSocket = null; } catch (Exception e) { error(new SocketIOException("Exception was thrown in onConnect()", e)); } break; case IOMessage.TYPE_HEARTBEAT: sendPlain("2::"); break; case IOMessage.TYPE_MESSAGE: try { findCallback(message).onMessage(message.getData(), remoteAcknowledge(message)); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in onMessage(String).\n" + "Message was: " + message.toString(), e)); } break; case IOMessage.TYPE_JSON_MESSAGE: try { // test if JSON is valid by catching a parse Exception objectMapper.readValue(message.getData(), new TypeReference<Map<String, Object>>() {}); // JSONUtils.getJsonGenericMap(message.getData(), objectMapper); findCallback(message).onMessage(message.getData(), remoteAcknowledge(message)); } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in onMessage(JSON).\n" + "Message was: " + message.toString(), e)); } break; case IOMessage.TYPE_EVENT: try { Map<String, Object> map = objectMapper.readValue( message.getData(), new TypeReference<Map<String, Object>>() {}); Object[] argsArray; if (map.containsKey("args")) { Object argsString = map.get("args"); List<Object> argObjects = objectMapper.readValue(argsString.toString(), new TypeReference<List<Object>>() {}); argsArray = new Object[argObjects.size()]; for (int i = 0; i < argObjects.size(); i++) { if (argObjects.get(i) != null) { argsArray[i] = argObjects.get(i); } } } else { argsArray = new Object[0]; } String eventName = map.get("name").toString(); try { findCallback(message).on(eventName, remoteAcknowledge(message), argsArray); } catch (Exception e) { error( new SocketIOException( "Exception was thrown in on(String, JSON[]).\n" + "Message was: " + message.toString(), e)); } } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (JsonMappingException e) { log.warn("Mapping JSON received: " + message.getData()); } catch (IOException e) { log.warn("IO Exception: " + message.getData()); } break; case IOMessage.TYPE_ACK: String[] data = message.getData().split("\\+", 2); if (data.length == 2) { try { int id = Integer.parseInt(data[0]); IOAcknowledge ack = acknowledge.get(id); if (ack == null) { log.warn("Received unknown ack packet"); } else { List<Object> argObjects = objectMapper.readValue(data[1].toString(), new TypeReference<List<Object>>() {}); Object[] argsArray = new Object[argObjects.size()]; for (int i = 0; i < argObjects.size(); i++) { if (argObjects.get(i) != null) { argsArray[i] = argObjects.get(i); } } ack.ack(argsArray); } } catch (NumberFormatException e) { log.warn( "Received malformated Acknowledge! This is potentially filling up the acknowledges!"); } catch (JsonParseException e) { log.warn("Malformated JSON received: " + message.getData()); } catch (JsonMappingException e) { log.warn("Mapping JSON received: " + message.getData()); } catch (IOException e) { log.warn("IO Exception: " + message.getData()); } } else if (data.length == 1) { sendPlain("6:::" + data[0]); } break; case IOMessage.TYPE_ERROR: try { findCallback(message).onError(new SocketIOException(message.getData())); } catch (SocketIOException e) { error(e); } if (message.getData().endsWith("+0")) { // We are advised to disconnect cleanup(); } break; case IOMessage.TYPE_NOOP: break; default: log.warn("Unkown type received" + message.getType()); break; } }