@Override
  public void RecvMessage(Message message) throws Exception {

    logger.debug("recv message :{}", message.getContent());

    synchronized (this) {
      if (this.userState != GSUserState.Login) {
        // TODO: may lost message
        return;
      }

      Gson gson = new Gson();

      String content = new String(message.getContent(), "UTF8");

      JsonObject json = (JsonObject) new JsonParser().parse(content);

      JsonArray bodies = json.getAsJsonArray("bodies");

      JsonObject object = (JsonObject) bodies.get(0);

      int messageType = object.get("messageBodyType").getAsInt();

      String id = json.get("id").toString();

      IPCMessage ipcMessage =
          new IPCMessage(id, message.getType(), message.getSource(), message.getTarget());

      ipcMessage.setContent(object.toString(), messageType);

      ipcMessage.setDirect(GSDirect.From);

      ipcMessage.setSeqID(message.getSeqID());

      ipcMessage.setState(GSMessageState.LocalApply);

      binderDataBase.saveMessage(ipcMessage, this);

      onMessageStateChanged(ipcMessage, GSError.SUCCESS);

      logger.debug("recv message :{} -- success", ipcMessage);
    }
  }
  @Override
  public void sendMessage(final IPCMessage ipcMessage) throws RemoteException {

    synchronized (this) {
      if (this.userState != GSUserState.Login) {

        ipcMessage.setState(GSMessageState.SendFailed);

        onMessageStateChanged(ipcMessage, GSError.LOGIN_FIRST);

        return;
      }

      ipcMessage.setSource(this.client.getUser());

      try {

        Gson gson = new Gson();

        JsonObject json = (JsonObject) gson.toJsonTree(ipcMessage);

        JsonArray bodies = new JsonArray();

        bodies.add(new JsonParser().parse(ipcMessage.getContent()));

        json.add("bodies", bodies);

        final String content = json.toString();

        logger.debug("send message :{}", content);

        ipcMessage.setState(GSMessageState.LocalApply);

        this.binderDataBase.saveMessage(ipcMessage, this);

        onMessageStateChanged(ipcMessage, GSError.SUCCESS);

        // create rpc message package
        Message message = new Message();

        message.setSeqID(ipcMessage.getSeqID());

        message.setSource(ipcMessage.getSource());

        message.setTarget(ipcMessage.getTarget());

        message.setType(ipcMessage.getType());

        message.setContent(content.getBytes("UTF-8"));

        imServer.sendMessage(ipcMessage.getId(), message);

        ipcMessage.setState(GSMessageState.Sending);

        this.binderDataBase.updateMessageState(ipcMessage.getId(), ipcMessage.getState());

        onMessageStateChanged(ipcMessage, GSError.SUCCESS);

      } catch (Exception e) {

        logger.error("send message({}) error", ipcMessage.getId(), e);

        ipcMessage.setState(GSMessageState.SendFailed);

        try {
          this.binderDataBase.updateMessageState(ipcMessage.getId(), ipcMessage.getState());
        } catch (Exception e1) {
          logger.error(
              "save message({}) state({}) error", ipcMessage.getId(), ipcMessage.getState(), e);
        }

        onMessageStateChanged(ipcMessage, GSError.UNKNOWN_ERROR);
      }
    }
  }