private void handle(BackupStorageDeletionMsg msg) {
    BackupStorageInventory inv = BackupStorageInventory.valueOf(self);
    extpEmitter.beforeDelete(inv);
    deleteHook();
    extpEmitter.afterDelete(inv);

    BackupStorageDeletionReply reply = new BackupStorageDeletionReply();
    tracker.untrackHook(self.getUuid());
    bus.reply(msg, reply);
  }
  protected void handle(final APIDetachBackupStorageFromZoneMsg msg) {
    final APIDetachBackupStorageFromZoneEvent evt =
        new APIDetachBackupStorageFromZoneEvent(msg.getId());

    try {
      extpEmitter.preDetach(self, msg.getZoneUuid());
    } catch (BackupStorageException e) {
      evt.setErrorCode(errf.instantiateErrorCode(BackupStorageErrors.DETACH_ERROR, e.getMessage()));
      bus.publish(evt);
      return;
    }

    extpEmitter.beforeDetach(self, msg.getZoneUuid());
    detachHook(
        new Completion(msg) {
          @Transactional
          private BackupStorageVO updateDb(BackupStorageVO vo, String zoneUuid) {
            dbf.entityForTranscationCallback(
                TransactionalCallback.Operation.REMOVE, BackupStorageZoneRefVO.class);
            String sql =
                "delete from BackupStorageZoneRefVO bz where bz.zoneUuid = :zoneUuid and bz.backupStorageUuid = :bsUuid";
            Query q = dbf.getEntityManager().createQuery(sql);
            q.setParameter("zoneUuid", zoneUuid);
            q.setParameter("bsUuid", vo.getUuid());
            q.executeUpdate();
            vo = dbf.getEntityManager().find(BackupStorageVO.class, vo.getUuid());
            return vo;
          }

          @Override
          public void success() {
            self = updateDb(self, msg.getZoneUuid());
            extpEmitter.afterDetach(self, msg.getZoneUuid());

            evt.setInventory(getSelfInventory());
            logger.debug(
                String.format(
                    "successfully detached backup storage[uuid:%s] from zone[uuid:%s]",
                    self.getUuid(), msg.getBackupStorageUuid()));
            bus.publish(evt);
          }

          @Override
          public void fail(ErrorCode errorCode) {
            logger.warn(errorCode.toString());
            extpEmitter.failToDetach(self, msg.getZoneUuid());
            evt.setErrorCode(
                errf.instantiateErrorCode(BackupStorageErrors.DETACH_ERROR, errorCode));
            bus.publish(evt);
          }
        });
  }
  protected void handle(final APIAttachBackupStorageToZoneMsg msg) {
    final APIAttachBackupStorageToZoneEvent evt =
        new APIAttachBackupStorageToZoneEvent(msg.getId());
    final BackupStorageVO svo = dbf.findByUuid(msg.getBackupStorageUuid(), BackupStorageVO.class);

    String err = extpEmitter.preAttach(svo, msg.getZoneUuid());
    if (err != null) {
      evt.setErrorCode(errf.instantiateErrorCode(BackupStorageErrors.ATTACH_ERROR, err));
      bus.publish(evt);
      return;
    }

    extpEmitter.beforeAttach(svo, msg.getZoneUuid());
    attachHook(
        msg.getZoneUuid(),
        new Completion(msg) {
          @Override
          public void success() {
            BackupStorageZoneRefVO rvo = new BackupStorageZoneRefVO();
            rvo.setBackupStorageUuid(svo.getUuid());
            rvo.setZoneUuid(msg.getZoneUuid());
            dbf.persist(rvo);

            refreshVO();
            extpEmitter.afterAttach(self, msg.getZoneUuid());

            evt.setInventory(getSelfInventory());
            logger.debug(
                String.format(
                    "successfully attached backup storage[uuid:%s, name:%s]",
                    self.getUuid(), self.getName()));
            bus.publish(evt);
          }

          @Override
          public void fail(ErrorCode errorCode) {
            logger.warn(errorCode.toString());
            extpEmitter.failToAttach(svo, msg.getZoneUuid());
            evt.setErrorCode(
                errf.instantiateErrorCode(BackupStorageErrors.ATTACH_ERROR, errorCode));
            bus.publish(evt);
          }
        });
  }
  protected void handle(APIChangeBackupStorageStateMsg msg) {
    APIChangeBackupStorageStateEvent evt = new APIChangeBackupStorageStateEvent(msg.getId());

    BackupStorageState currState = self.getState();
    BackupStorageStateEvent event = BackupStorageStateEvent.valueOf(msg.getStateEvent());
    BackupStorageState nextState = AbstractBackupStorage.getNextState(currState, event);

    try {
      extpEmitter.preChange(self, event);
    } catch (BackupStorageException e) {
      evt.setErrorCode(
          errf.instantiateErrorCode(SysErrors.CHANGE_RESOURCE_STATE_ERROR, e.getMessage()));
      bus.publish(evt);
      return;
    }

    extpEmitter.beforeChange(self, event);
    changeStateHook(event, nextState);
    self.setState(nextState);
    self = dbf.updateAndRefresh(self);
    extpEmitter.afterChange(self, event, currState);
    evt.setInventory(getSelfInventory());
    bus.publish(evt);
  }