public void logout() throws Exception {
    Map<String, String> param1 = new HashMap<String, String>();
    param1.put(ObjectElement.OPERATION_KEY, Tl1CommandCode.CANC_USER.toString());
    param1.put("UID", neInfo.getUserProfile().getUserID());
    TL1RequestMessage logoutMessage = new TL1RequestMessage(Tl1CommandCode.CANC_USER, param1);
    AbstractTL1SendHelper helper = new TL1SynchSendHelper(neInfo, logoutMessage, composer, parser);
    tl1Engine.send(helper);

    // terminate = true;
    // associationThread. interrupt();

    TL1ResponseMessage response = helper.getTL1ResponseMessage();
    if (!response.getCompletionCode().equals(TL1Constants.COMPLETED)) {
      // String payload[] = response.getTextBlocks();

      throw new Exception("Failed to log out " + response);
    }
  }
    @Override
    public void run() {

      TL1AssociationEvent event;
      while (!terminate) {
        synchronized (lock) {
          try {
            int sleep = speedup ? delay / skipCount : delay;
            lock.wait(sleep);
          } catch (Exception e) {
            log.error("Warning - KeepAlive: ", e);
            break;
          }
        }
        event = null;
        if (sendKeepAlive) {
          AbstractTL1SendHelper helper =
              new TL1SynchSendHelper(neInfo, keepAliveMessage, composer, parser);
          helper.setTimeout(timeout);
          try {
            tl1Engine.send(helper);
          } catch (Exception se) {
            log.debug("Failed to communication with NE " + neInfo.getNeName(), se);
            event = new TL1AssociationEvent(TL1AssociationEvent.ASSOCIATION_DOWN, neInfo);
            sendKeepAlive = false;
            registerListener.receiveEvent(event);
            continue;
          }
          TL1ResponseMessage response = helper.getTL1ResponseMessage();

          // If tid change, that is it. Bring down the association.
          if (!response.getTid().equals(neInfo.getNetworkElementName())) {
            log.error(
                "Problem - Association response with TID change: "
                    + response.getCommand()
                    + " "
                    + response.getTid()
                    + " "
                    + response.getCompletionCode()
                    + " "
                    + response.getDate()
                    + "\n"
                    + response.toString());
            event = new TL1AssociationEvent(TL1AssociationEvent.WRONG_TID, neInfo);
            sendKeepAlive = false;
            skipCount = 1;
            registerListener.receiveEvent(event);
            continue;
          }

          /*
           * if (response.getCompletionCode() == null) { if
           * (!tl1Engine.isConnected()) { try {
           * tl1Engine.connect(neInfo.getAddressInfo().getPrimaryIPAddress(),
           * neInfo.getAddressInfo().getPrimaryPort()); } catch (Exception e) {
           *  } } continue; }
           */
          // cannot bring the association down because of output is
          // ill-formatted for some
          // strange reason i.e. high rate.
          if (response.getInternalCompletionCode() != TL1ResponseMessage.COMPLETION_CODE.SUCCESS
              && response.getInternalCompletionCode() != TL1ResponseMessage.COMPLETION_CODE.TIME_OUT
              && response.getCompletionCode().equals(TL1ResponseMessage.UNKNOWN)) {
            log.error(
                "Warning - Unknown completion code with "
                    + "Internal Code = "
                    + response.getInternalCompletionCode()
                    + " for "
                    + response.getTid()
                    + " Ctag "
                    + response.getCtag()
                    + "\n"
                    + response.toString());
            continue;
          }

          // TL1 output still processed, who cares if heartbeat output is not
          // arrived yet
          if (response.getInternalCompletionCode() == TL1ResponseMessage.COMPLETION_CODE.TIME_OUT
              && tl1Engine.getMessageQueueSize() > 0) {
            skipCount = 1;

            continue;
          }
          if (!TL1Constants.COMPLETED.equals(response.getCompletionCode())) {
            /*
             * We do not raise the association down until heartbeat fails 3
             * times for whatever the reason is.
             */
            if (skipCount <= skip) {

              skipCount++;
              continue;
            }
            log.debug(
                "Exception - Association down - could not contact NE: "
                    + response.getCommand()
                    + " "
                    + response.getTid()
                    + " "
                    + response.getCompletionCode()
                    + " "
                    + response.getDate()
                    + "\n"
                    + response.toString());
            event = new TL1AssociationEvent(TL1AssociationEvent.ASSOCIATION_DOWN, neInfo);
          }
          if (registerListener != null && event != null) {
            sendKeepAlive = false;
            registerListener.receiveEvent(event);
          }
          skipCount = 1;
        }
      }
    }
  public void login() throws Exception {
    tl1Engine.addPropertyChangeListener(TL1LanguageEngine.CONNECTED, this);

    AbstractTL1SendHelper helper =
        new TL1SynchSendHelper(neInfo, keepAliveMessage, composer, parser);
    tl1Engine.send(helper);
    TL1ResponseMessage response = helper.getTL1ResponseMessage();
    if (!response.getTid().equals(neInfo.getNetworkElementName())) {
      neInfo.setNeName(response.getTid());
      log.debug(
          "Updated TID to <"
              + response.getTid()
              + "> for "
              + neInfo.getAddressInfo().getPrimaryIPAddress()
              + " "
              + neInfo.getAddressInfo().getPrimaryPort());
    }

    /**
     * WP: June 2009. Globally only permit a single ACT-USER command to be outstanding at once. Why?
     * Thanks to OMEA stupidity, if the NE is set to use OMEA for radius authentication then we hit
     * a bug with OMEA. OMEA can only process a single RADIUS login request at a time, if we have 10
     * threads all trying to login to NEs after a restart we'll have 10 outstanding RADIUS requests
     * and most/all will fail and mess us up big time. We used to globally restrict the number of
     * worker threads to just 1, but that slows down the rest of DRAC, especially if we have > 1 NE
     * that are unreachable, we'll spend too much time trying to reconnect to the dead NEs. Instead
     * we lock just the ACT-USER phase.
     */
    synchronized (GLOBAL_ACT_USER_LOCK) {
      helper = new TL1SynchSendHelper(neInfo, buildLoginMsg(), composer, parser);
      tl1Engine.send(helper);
      response = helper.getTL1ResponseMessage();
    }

    TL1AssociationEvent event;

    // Check for TID
    if (!response.getTid().equals(neInfo.getNetworkElementName())) {
      event = new TL1AssociationEvent(TL1AssociationEvent.WRONG_TID, neInfo);
      if (heartBeatThread != null) {
        heartBeatThread.disableKeepAlive();
      }

      if (registerListener != null) {
        registerListener.receiveEvent(event);
      }
      return;
    }
    if (!response.getCompletionCode().equals(TL1Constants.COMPLETED)) {
      Exception ex = new Exception("AssciationException: failed to login"); // comment

      throw ex;
    }
    if (registerListener != null) {
      event = new TL1AssociationEvent(TL1AssociationEvent.ASSOCIATION_UP, neInfo);
      registerListener.receiveEvent(event);
    } else {
      log.debug(
          "Association:  No listener "
              + neInfo.getNetworkElementName()
              + " for event ASSOCIATION_UP");
    }

    heartBeatStarts();
  }