protected PrimaryStorageVO updatePrimaryStorage(APIUpdatePrimaryStorageMsg msg) {
    boolean update = false;
    if (msg.getName() != null) {
      self.setName(msg.getName());
      update = true;
    }
    if (msg.getDescription() != null) {
      self.setDescription(msg.getDescription());
      update = true;
    }

    return update ? self : null;
  }
  @Transactional
  private void updateCapacity(long total, long avail) {
    PrimaryStorageCapacityVO cvo =
        dbf.getEntityManager()
            .find(PrimaryStorageCapacityVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE);
    DebugUtils.Assert(
        cvo != null,
        String.format("how can there is no PrimaryStorageCapacityVO[uuid:%s]", self.getUuid()));

    cvo.setTotalPhysicalCapacity(total);
    cvo.setAvailablePhysicalCapacity(avail);
    dbf.getEntityManager().merge(cvo);
  }
 @Transactional(readOnly = true)
 private void checkIfBackupStorageAttachedToMyZone(String bsUuid) {
   String sql =
       "select bs.uuid from BackupStorageVO bs, BackupStorageZoneRefVO ref where bs.uuid = ref.backupStorageUuid and ref.zoneUuid = :zoneUuid and bs.uuid = :bsUuid";
   TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
   q.setParameter("zoneUuid", self.getZoneUuid());
   q.setParameter("bsUuid", bsUuid);
   if (q.getResultList().isEmpty()) {
     throw new OperationFailureException(
         errf.stringToOperationError(
             String.format(
                 "backup storage[uuid:%s] is not attached to zone[uuid:%s] the primary storage[uuid:%s] belongs to",
                 bsUuid, self.getZoneUuid(), self.getUuid())));
   }
 }
 @Override
 public PrimaryStorageInventory createPrimaryStorage(
     PrimaryStorageVO vo, APIAddPrimaryStorageMsg msg) {
   vo.setMountPath(msg.getUrl());
   vo = dbf.persistAndRefresh(vo);
   return PrimaryStorageInventory.valueOf(vo);
 }
  private void handle(final ConnectPrimaryStorageMsg msg) {
    final ConnectPrimaryStorageReply reply = new ConnectPrimaryStorageReply();
    self.setStatus(PrimaryStorageStatus.Connecting);
    self = dbf.updateAndRefresh(self);
    connectHook(
        msg,
        new Completion(msg) {
          @Override
          public void success() {
            self = dbf.reload(self);
            self.setStatus(PrimaryStorageStatus.Connected);
            self = dbf.updateAndRefresh(self);
            reply.setConnected(true);
            logger.debug(
                String.format("successfully connected primary storage[uuid:%s]", self.getUuid()));
            bus.reply(msg, reply);
          }

          @Override
          public void fail(ErrorCode errorCode) {
            if (msg.isNewAdded()) {
              reply.setError(errorCode);
            } else {
              self.setStatus(PrimaryStorageStatus.Disconnected);
              self = dbf.updateAndRefresh(self);
              logger.debug(
                  String.format(
                      "failed to connect primary storage[uuid:%s], %s", self.getUuid(), errorCode));
              reply.setConnected(false);
            }

            bus.reply(msg, reply);
          }
        });
  }
  protected void handle(APIChangePrimaryStorageStateMsg msg) {
    APIChangePrimaryStorageStateEvent evt = new APIChangePrimaryStorageStateEvent(msg.getId());

    PrimaryStorageState currState = self.getState();
    PrimaryStorageStateEvent event = PrimaryStorageStateEvent.valueOf(msg.getStateEvent());
    PrimaryStorageState nextState = AbstractPrimaryStorage.getNextState(currState, event);

    try {
      extpEmitter.preChange(self, event);
    } catch (PrimaryStorageException 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(PrimaryStorageInventory.valueOf(self));
    bus.publish(evt);
  }
  private void handle(final APISyncPrimaryStorageCapacityMsg msg) {
    final APISyncPrimaryStorageCapacityEvent evt =
        new APISyncPrimaryStorageCapacityEvent(msg.getId());

    FlowChain chain = FlowChainBuilder.newShareFlowChain();
    chain.setName(String.format("sync-capacity-of-primary-storage-%s", self.getUuid()));
    chain
        .then(
            new ShareFlow() {
              Long volumeUsage;
              Long snapshotUsage;
              Long totalPhysicalSize;
              Long availablePhysicalSize;

              @Override
              public void setup() {
                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volumes";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                VolumeReportPrimaryStorageCapacityUsageReply r = reply.castReply();
                                volumeUsage = r.getUsedCapacity();
                                volumeUsage =
                                    ratioMgr.calculateByRatio(self.getUuid(), volumeUsage);
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volume-snapshots";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeSnapshotReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeSnapshotReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeSnapshotConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                // note: snapshot size is physical size,
                                // don't calculate over-provisioning here
                                VolumeSnapshotReportPrimaryStorageCapacityUsageReply r =
                                    reply.castReply();
                                snapshotUsage = r.getUsedSize();
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-physical-capacity";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        syncPhysicalCapacity(
                            new ReturnValueCompletion<PhysicalCapacityUsage>(trigger) {
                              @Override
                              public void success(PhysicalCapacityUsage returnValue) {
                                totalPhysicalSize = returnValue.totalPhysicalSize;
                                availablePhysicalSize = returnValue.availablePhysicalSize;
                                availablePhysicalSize =
                                    availablePhysicalSize < 0 ? 0 : availablePhysicalSize;
                                trigger.next();
                              }

                              @Override
                              public void fail(ErrorCode errorCode) {
                                trigger.fail(errorCode);
                              }
                            });
                      }
                    });

                done(
                    new FlowDoneHandler(msg) {
                      @Override
                      public void handle(Map data) {
                        writeToDb();
                        self = dbf.reload(self);
                        evt.setInventory(getSelfInventory());
                        bus.publish(evt);
                      }

                      private void writeToDb() {
                        PrimaryStorageCapacityUpdater updater =
                            new PrimaryStorageCapacityUpdater(self.getUuid());
                        updater.run(
                            new PrimaryStorageCapacityUpdaterRunnable() {
                              @Override
                              public PrimaryStorageCapacityVO call(PrimaryStorageCapacityVO cap) {
                                long avail = cap.getTotalCapacity() - volumeUsage - snapshotUsage;
                                cap.setAvailableCapacity(avail);
                                cap.setAvailablePhysicalCapacity(availablePhysicalSize);
                                cap.setTotalPhysicalCapacity(totalPhysicalSize);
                                return cap;
                              }
                            });
                      }
                    });

                error(
                    new FlowErrorHandler(msg) {
                      @Override
                      public void handle(ErrorCode errCode, Map data) {
                        evt.setErrorCode(errCode);
                        bus.publish(evt);
                      }
                    });
              }
            })
        .start();
  }
 protected String getSyncId() {
   return String.format("primaryStorage-%s", self.getUuid());
 }