code: @Override
      public void close() {
          if (closing.compareAndSet(false, true)) {
              super.close();
              log.debug("IO Session closing: {}", (ioSession != null ? ioSession.isClosing() : null));
              if (ioSession != null && !ioSession.isClosing()) {
                  // set a ref to ourself so that the handler can be notified when close future is done
                  final RTMPMinaConnection self = this;
                  // close now, no flushing, no waiting
                  final CloseFuture future = ioSession.closeNow();
                  log.debug("Connection close future: {}", future);
                  IoFutureListener<CloseFuture> listener = new IoFutureListener<CloseFuture>() {
                      public void operationComplete(CloseFuture future) {
                          if (future.isClosed()) {
                              log.info("Connection is closed: {}", getSessionId());
                              if (log.isTraceEnabled()) {
                                  log.trace("Session id - local: {} session: {}", getSessionId(), (String) ioSession.removeAttribute(RTMPConnection.RTMP_SESSION_ID));
                              }
                              handler.connectionClosed(self);
                          } else {
                              log.debug("Connection is not yet closed");
                          }
                          future.removeListener(this);
                      }
                  };
                  future.addListener(listener);
              }
              log.debug("Connection state: {}", getState());
              if (getStateCode() != RTMP.STATE_DISCONNECTED) {
                  handler.connectionClosed(this);
              }
              // de-register with JMX
              unregisterJMX();
          } else if (log.isDebugEnabled()) {
              log.debug("Close has already been called");
          }
      }
docs: {@inheritDoc}