public void close() {
   boolean wasClosed = false;
   synchronized (this) {
     if (!isClosed()) {
       try {
         if (session != null) {
           session.setStatus(Session.STATUS_CLOSED);
         }
         synchronized (writer) {
           try {
             // Register that we started sending data on the connection
             writeStarted();
             writer.write("</stream:stream>");
             if (flashClient) {
               writer.write('\0');
             }
             writer.flush();
           } catch (IOException e) {
           } finally {
             // Register that we finished sending data on the connection
             writeFinished();
           }
         }
       } catch (Exception e) {
         Log.error(
             LocaleUtils.getLocalizedString("admin.error.close") + "\n" + this.toString(), e);
       }
       closeConnection();
       wasClosed = true;
     }
   }
   if (wasClosed) {
     notifyCloseListeners();
   }
 }
 /**
  * Forces the connection to be closed immediately no matter if closing the socket takes a long
  * time. This method should only be called from {@link SocketSendingTracker} when sending data
  * over the socket has taken a long time and we need to close the socket, discard the connection
  * and its session.
  */
 private void forceClose() {
   if (session != null) {
     // Set that the session is closed. This will prevent threads from trying to
     // deliver packets to this session thus preventing future locks.
     session.setStatus(Session.STATUS_CLOSED);
   }
   closeConnection();
   // Notify the close listeners so that the SessionManager can send unavailable
   // presences if required.
   notifyCloseListeners();
 }