@Override
  public ReleaseCallbackResponse releaseCallback(ReleaseCallback releaseCallback) {
    CallbackRequestType request = releaseCallback.getReleaseCallback();
    this.logger.debug(
        "Received "
            + this.getClass().getSimpleName()
            + "#releaseCallback with params: rigname="
            + request.getName()
            + ", success="
            + request.getSuccess());

    ReleaseCallbackResponse response = new ReleaseCallbackResponse();
    ProviderResponse status = new ProviderResponse();
    response.setReleaseCallbackResponse(status);

    /* Load rig information. */
    RigDao dao = new RigDao();
    Rig rig = dao.findByName(request.getName());
    if (rig == null) {
      /* If the rig wasn't found something is seriously wrong. */
      this.logger.error(
          "Received release notification from rig '"
              + request.getName()
              + "' which does not "
              + "exist.");
      status.setSuccessful(false);
    } else if (request.getSuccess()) {
      status.setSuccessful(true);

      /* Release was successful so provide the rig back to the queue. */
      this.logger.debug(
          "Release of rig '" + request.getName() + "' successful, going to requeue rig.");
      rig.setInSession(false);
      rig.setSession(null);
      rig.setLastUpdateTimestamp(new Date());
      dao.flush();

      /* Provide notification a new rig is free. */
      RigProviderActivator.notifyRigEvent(RigStateChangeEvent.ONLINE, rig, dao.getSession());
    } else {
      status.setSuccessful(true);

      /* Allocation failed so take the rig off line. */
      rig.setInSession(false);
      rig.setSession(null);
      rig.setLastUpdateTimestamp(new Date());
      rig.setOnline(false);

      RigLogDao logDao = new RigLogDao(dao.getSession());

      ErrorType err = request.getError();
      if (err == null) {
        this.logger.warn("Taking rig '" + request.getName() + "' offline because release failed.");
        rig.setOfflineReason("Release failed.");
        logDao.addOfflineLog(rig, "Release failed.");
      } else {
        this.logger.warn(
            "Taking rig '"
                + request.getName()
                + "' offline because release failed with reason '"
                + err.getReason()
                + "'.");
        rig.setOfflineReason("Release failed with reason: " + err.getReason());
        logDao.addOfflineLog(rig, "Release failed with reason: " + err.getReason());
      }

      /* Provide notification a new rig is offline. */
      RigProviderActivator.notifyRigEvent(RigStateChangeEvent.OFFLINE, rig, dao.getSession());
    }

    dao.flush();
    dao.closeSession();
    return response;
  }
  @Override
  public AllocateCallbackResponse allocateCallback(AllocateCallback allocateCallback) {
    CallbackRequestType request = allocateCallback.getAllocateCallback();
    this.logger.debug(
        "Received "
            + this.getClass().getSimpleName()
            + "#allocateCallback with params: rigname="
            + request.getName()
            + ", success="
            + request.getSuccess()
            + '.');

    AllocateCallbackResponse response = new AllocateCallbackResponse();
    ProviderResponse status = new ProviderResponse();
    response.setAllocateCallbackResponse(status);

    /* Load session from rig. */
    RigDao dao = new RigDao();
    Rig rig = dao.findByName(request.getName());
    Session ses = null;
    if (rig == null) {
      /* If the rig wasn't found, something is seriously wrong. */
      this.logger.error(
          "Received allocate callback for rig '" + request.getName() + "' that doesn't exist.");
      status.setSuccessful(false);
    } else if ((ses = rig.getSession()) == null) {
      this.logger.warn(
          "Received allocate callback for session that doesn't exist. Rig who sent callback "
              + "response was '"
              + request.getName()
              + "'.");
      status.setSuccessful(false);

      /* Make sure the rig is no marked as in session. */
      rig.setInSession(false);
      rig.setLastUpdateTimestamp(new Date());
    } else if (request.getSuccess()) {
      /* If the response from allocate is successful, put the session to ready. */
      ses.setReady(true);
      status.setSuccessful(true);
      rig.setLastUpdateTimestamp(new Date());

      RigProviderActivator.notifySessionEvent(SessionEvent.READY, ses, dao.getSession());
    } else {
      ErrorType err = request.getError();
      this.logger.error(
          "Received allocate response for "
              + ses.getUserNamespace()
              + ':'
              + ses.getUserName()
              + ", allocation not successful. Error reason is '"
              + err.getReason()
              + "'.");

      /* Allocation failed so end the session and take the rig offline depending on error. */
      ses.setActive(false);
      ses.setReady(false);
      ses.setRemovalReason("Allocation failure with reason: " + err.getReason());
      ses.setRemovalTime(new Date());

      RigProviderActivator.notifySessionEvent(SessionEvent.FINISHED, ses, dao.getSession());

      if (err.getCode() == 4) // Error code 4 is an existing session exists
      {
        this.logger.error(
            "Allocation failure reason was caused by an existing session, so not putting rig offline "
                + "because a session already has it.");
      } else {
        rig.setInSession(false);
        rig.setOnline(false);
        rig.setOfflineReason("Allocation failed with reason: " + err.getReason());
        rig.setSession(null);

        /* Log the rig going offline. */
        RigLogDao logDao = new RigLogDao(dao.getSession());
        logDao.addOfflineLog(rig, "Allocation failed with reason: " + err.getReason() + "");

        RigProviderActivator.notifyRigEvent(RigStateChangeEvent.OFFLINE, rig, dao.getSession());
      }

      rig.setLastUpdateTimestamp(new Date());

      /* Whilst allocation was not successful, the process was clean. */
      status.setSuccessful(true);
    }

    dao.flush();
    dao.closeSession();
    return response;
  }