public void shutdown() {
   retries = -1;
   if (channel != null) {
     try {
       channel.disconnect();
       channel.close();
     } catch (Throwable e) {
       Flog.error(e);
     }
     channel = null;
   }
 }
 public void write(Serializable obj) {
   // TODO: threading issue. lock channel
   if (channel == null) {
     Flog.error("not writing because no channel");
     return;
   }
   String data = new Gson().toJson(obj);
   if (channel == null) {
     Flog.error("Lost connection? Not writing because no channel. Also, race condition!");
     return;
   }
   channel.writeAndFlush(data + "\n");
 }
  protected void connect() {
    if (retries <= 0) {
      Flog.error("I give up connecting.");
      return;
    }
    retries -= 1;
    FlooUrl flooUrl = handler.getUrl();
    final String host;
    final int port;

    if (flooUrl.host.equals(Constants.floobitsDomain) && retries % 4 == 0) {
      host = Constants.OUTBOUND_FILTER_PROXY_HOST;
      port = Constants.OUTBOUND_FILTER_PROXY_PORT;
    } else {
      host = flooUrl.host;
      port = flooUrl.port;
    }

    if (channel == null) {
      _connect(host, port);
      return;
    }
    try {
      channel
          .close()
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                  channel = null;
                  _connect(host, port);
                }
              });
    } catch (Throwable e) {
      Flog.error(e);
      reconnect();
    }
  }