@Override
 public void afterHostConnected(HostInventory host) {
   SimpleQuery<LocalStorageHostRefVO> q = dbf.createQuery(LocalStorageHostRefVO.class);
   q.add(LocalStorageHostRefVO_.hostUuid, Op.EQ, host.getUuid());
   LocalStorageHostRefVO ref = q.find();
   if (ref != null) {
     RecalculatePrimaryStorageCapacityMsg msg = new RecalculatePrimaryStorageCapacityMsg();
     msg.setPrimaryStorageUuid(ref.getPrimaryStorageUuid());
     bus.makeTargetServiceIdByResourceUuid(
         msg, PrimaryStorageConstant.SERVICE_ID, ref.getPrimaryStorageUuid());
     bus.send(msg);
   }
 }
 @Override
 @Transactional(readOnly = true)
 public HostMaintenancePolicy getHostMaintenancePolicy(HostInventory host) {
   String sql =
       "select count(ps) from PrimaryStorageVO ps, PrimaryStorageClusterRefVO ref where ps.uuid = ref.primaryStorageUuid"
           + " and ps.type = :type and ref.clusterUuid = :cuuid";
   TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class);
   q.setParameter("type", LocalStorageConstants.LOCAL_STORAGE_TYPE);
   q.setParameter("cuuid", host.getClusterUuid());
   q.setMaxResults(1);
   Long count = q.getSingleResult();
   return count > 0 ? HostMaintenancePolicy.StopVm : null;
 }
 @Override
 public void afterDeleteHost(final HostInventory inventory) {
   final String priUuid = getLocalStorageInCluster(inventory.getClusterUuid());
   if (priUuid != null) {
     RemoveHostFromLocalStorageMsg msg = new RemoveHostFromLocalStorageMsg();
     msg.setPrimaryStorageUuid(priUuid);
     msg.setHostUuid(inventory.getUuid());
     bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, priUuid);
     MessageReply reply = bus.call(msg);
     if (!reply.isSuccess()) {
       // TODO
       logger.warn(
           String.format(
               "failed to remove host[uuid:%s] from local primary storage[uuid:%s], %s",
               inventory.getUuid(), priUuid, reply.getError()));
     } else {
       logger.debug(
           String.format(
               "removed host[uuid:%s] from local primary storage[uuid:%s]",
               inventory.getUuid(), priUuid));
     }
   }
 }
  @Override
  public void beforeDeleteHost(final HostInventory inventory) {
    SimpleQuery<LocalStorageHostRefVO> q = dbf.createQuery(LocalStorageHostRefVO.class);
    q.select(LocalStorageHostRefVO_.primaryStorageUuid);
    q.add(LocalStorageHostRefVO_.hostUuid, Op.EQ, inventory.getUuid());
    final String psUuid = q.findValue();
    if (psUuid == null) {
      return;
    }

    logger.debug(
        String.format(
            "the host[uuid:%s] belongs to the local storage[uuid:%s], starts to delete vms and"
                + " volumes on the host",
            inventory.getUuid(), psUuid));

    final List<String> vmUuids =
        new Callable<List<String>>() {
          @Override
          @Transactional(readOnly = true)
          public List<String> call() {
            String sql =
                "select vm.uuid from VolumeVO vol, LocalStorageResourceRefVO ref, VmInstanceVO vm where ref.primaryStorageUuid = :psUuid"
                    + " and vol.type = :vtype and ref.resourceUuid = vol.uuid and ref.resourceType = :rtype and ref.hostUuid = :huuid"
                    + " and vm.uuid = vol.vmInstanceUuid";
            TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
            q.setParameter("vtype", VolumeType.Root);
            q.setParameter("rtype", VolumeVO.class.getSimpleName());
            q.setParameter("huuid", inventory.getUuid());
            q.setParameter("psUuid", psUuid);
            return q.getResultList();
          }
        }.call();

    // destroy vms
    if (!vmUuids.isEmpty()) {
      List<DestroyVmInstanceMsg> msgs =
          CollectionUtils.transformToList(
              vmUuids,
              new Function<DestroyVmInstanceMsg, String>() {
                @Override
                public DestroyVmInstanceMsg call(String uuid) {
                  DestroyVmInstanceMsg msg = new DestroyVmInstanceMsg();
                  msg.setVmInstanceUuid(uuid);
                  bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, uuid);
                  return msg;
                }
              });

      final FutureCompletion completion = new FutureCompletion();
      bus.send(
          msgs,
          new CloudBusListCallBack(completion) {
            @Override
            public void run(List<MessageReply> replies) {
              for (MessageReply r : replies) {
                if (!r.isSuccess()) {
                  String vmUuid = vmUuids.get(replies.indexOf(r));
                  // TODO
                  logger.warn(
                      String.format("failed to destroy the vm[uuid:%s], %s", vmUuid, r.getError()));
                }
              }

              completion.success();
            }
          });

      completion.await(TimeUnit.MINUTES.toMillis(15));
    }

    final List<String> volUuids =
        new Callable<List<String>>() {
          @Override
          @Transactional(readOnly = true)
          public List<String> call() {
            String sql =
                "select vol.uuid from VolumeVO vol, LocalStorageResourceRefVO ref where ref.primaryStorageUuid = :psUuid"
                    + " and vol.type = :vtype and ref.resourceUuid = vol.uuid and ref.resourceType = :rtype and ref.hostUuid = :huuid";
            TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
            q.setParameter("psUuid", psUuid);
            q.setParameter("vtype", VolumeType.Data);
            q.setParameter("rtype", VolumeVO.class.getSimpleName());
            q.setParameter("huuid", inventory.getUuid());
            return q.getResultList();
          }
        }.call();

    // delete data volumes
    if (!volUuids.isEmpty()) {
      List<DeleteVolumeMsg> msgs =
          CollectionUtils.transformToList(
              volUuids,
              new Function<DeleteVolumeMsg, String>() {
                @Override
                public DeleteVolumeMsg call(String uuid) {
                  DeleteVolumeMsg msg = new DeleteVolumeMsg();
                  msg.setUuid(uuid);
                  msg.setDetachBeforeDeleting(true);
                  bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, uuid);
                  return msg;
                }
              });

      final FutureCompletion completion = new FutureCompletion();
      bus.send(
          msgs,
          new CloudBusListCallBack(completion) {
            @Override
            public void run(List<MessageReply> replies) {
              for (MessageReply r : replies) {
                if (!r.isSuccess()) {
                  String uuid = volUuids.get(replies.indexOf(r));
                  // TODO
                  logger.warn(
                      String.format(
                          "failed to delete the data volume[uuid:%s], %s", uuid, r.getError()));
                }
              }

              completion.success();
            }
          });

      completion.await(TimeUnit.MINUTES.toMillis(15));
    }
  }