@Override
  public void virtualMachineRemoved(VirtualMachine virtualMachine) {

    movingAverageStatistics.clear(virtualMachine.getUid());

    final String groupUid = generateGroupUid(virtualMachine.getUid());
    Alert[] alertsByGroupUid =
        ((InternalAlertManager) admin.getAlertManager())
            .getAlertRepository()
            .getAlertsByGroupUid(groupUid);
    if (alertsByGroupUid.length != 0 && !alertsByGroupUid[0].getStatus().isResolved()) {
      AlertFactory factory = new AlertFactory();
      factory.name(ALERT_NAME);
      factory.groupUid(groupUid);
      factory.description(
          AlertBeanUtils.getGridComponentShortName(virtualMachine)
              + " Heap memory is unavailable; JVM has been removed");
      factory.severity(AlertSeverity.WARNING);
      factory.status(AlertStatus.NA);
      factory.componentUid(virtualMachine.getUid());
      factory.componentDescription(AlertBeanUtils.getGridComponentDescription(virtualMachine));
      factory.config(config.getProperties());

      Alert alert = factory.toAlert();
      admin.getAlertManager().triggerAlert(new HeapMemoryUtilizationAlert(alert));
    }
  }
  @Override
  public void afterPropertiesSet() throws Exception {
    validateProperties();

    long measurementPeriod = config.getMeasurementPeriod();
    int period = (int) (measurementPeriod / StatisticsMonitor.DEFAULT_MONITOR_INTERVAL);
    movingAverageStatistics = new MovingAverageStatistics(period);

    admin.getVirtualMachines().getVirtualMachineRemoved().add(this);
    admin.getVirtualMachines().getVirtualMachineStatisticsChanged().add(this);
    admin.getVirtualMachines().startStatisticsMonitor();
  }
 @Override
 public void setProperties(Map<String, String> properties) {
   config.setProperties(properties);
 }
 @Override
 public Map<String, String> getProperties() {
   return config.getProperties();
 }
 private String getPeriodOfTime(VirtualMachineStatisticsChangedEvent event) {
   return TimeUtil.format(config.getMeasurementPeriod());
 }
  @Override
  public void virtualMachineStatisticsChanged(VirtualMachineStatisticsChangedEvent event) {

    int highThreshold = config.getHighThresholdPerc();
    int lowThreshold = config.getLowThresholdPerc();

    double memoryAvg = calcAverageWithinPeriod(event);
    if (memoryAvg < 0) return; // period hasn't passed

    if (memoryAvg > highThreshold) {
      final String groupUid = generateGroupUid(event.getVirtualMachine().getUid());
      AlertFactory factory = new AlertFactory();
      factory.name(ALERT_NAME);
      factory.groupUid(groupUid);
      factory.description(
          AlertBeanUtils.getGridComponentShortName(event.getVirtualMachine())
              + " Heap memory crossed above a "
              + highThreshold
              + "% threshold, for a period of "
              + TimeUtil.format(config.getMeasurementPeriod())
              + ", with an average memory of "
              + NUMBER_FORMAT.format(memoryAvg)
              + "%");
      factory.severity(AlertSeverity.WARNING);
      factory.status(AlertStatus.RAISED);
      factory.componentUid(event.getVirtualMachine().getUid());
      factory.componentDescription(
          AlertBeanUtils.getGridComponentDescription(event.getVirtualMachine()));
      factory.config(config.getProperties());

      factory.putProperty(
          HeapMemoryUtilizationAlert.HOST_ADDRESS,
          event.getVirtualMachine().getMachine().getHostAddress());
      factory.putProperty(
          HeapMemoryUtilizationAlert.HOST_NAME,
          event.getVirtualMachine().getMachine().getHostName());
      factory.putProperty(
          HeapMemoryUtilizationAlert.CPU_UTILIZATION,
          AlertBeanUtils.getCpuPercToString(event.getStatistics().getCpuPerc()));
      factory.putProperty(
          HeapMemoryUtilizationAlert.PROCESS_ID,
          String.valueOf(event.getVirtualMachine().getDetails().getPid()));
      factory.putProperty(
          HeapMemoryUtilizationAlert.COMPONENT_NAME,
          AlertBeanUtils.getGridComponentFullName(event.getVirtualMachine()));
      factory.putProperty(
          HeapMemoryUtilizationAlert.HEAP_UTILIZATION,
          String.valueOf(event.getStatistics().getMemoryHeapUsedPerc()));
      factory.putProperty(
          HeapMemoryUtilizationAlert.MAX_HEAP_IN_BYTES,
          String.valueOf(event.getVirtualMachine().getDetails().getMemoryHeapMaxInBytes()));

      Alert alert = factory.toAlert();
      admin.getAlertManager().triggerAlert(new HeapMemoryUtilizationAlert(alert));

    } else if (memoryAvg < lowThreshold) {
      final String groupUid = generateGroupUid(event.getVirtualMachine().getUid());
      Alert[] alertsByGroupUid =
          ((InternalAlertManager) admin.getAlertManager())
              .getAlertRepository()
              .getAlertsByGroupUid(groupUid);
      if (alertsByGroupUid.length != 0 && !alertsByGroupUid[0].getStatus().isResolved()) {
        AlertFactory factory = new AlertFactory();
        factory.name(ALERT_NAME);
        factory.groupUid(groupUid);
        factory.description(
            AlertBeanUtils.getGridComponentShortName(event.getVirtualMachine())
                + " Heap memory crossed below a "
                + lowThreshold
                + "% threshold, for a period of "
                + getPeriodOfTime(event)
                + ", with an average memory of "
                + NUMBER_FORMAT.format(memoryAvg)
                + "%");
        factory.severity(AlertSeverity.WARNING);
        factory.status(AlertStatus.RESOLVED);
        factory.componentUid(event.getVirtualMachine().getUid());
        factory.componentDescription(
            AlertBeanUtils.getGridComponentDescription(event.getVirtualMachine()));
        factory.config(config.getProperties());

        factory.putProperty(
            HeapMemoryUtilizationAlert.HOST_ADDRESS,
            event.getVirtualMachine().getMachine().getHostAddress());
        factory.putProperty(
            HeapMemoryUtilizationAlert.HOST_NAME,
            event.getVirtualMachine().getMachine().getHostName());
        factory.putProperty(
            HeapMemoryUtilizationAlert.CPU_UTILIZATION,
            AlertBeanUtils.getCpuPercToString(event.getStatistics().getCpuPerc()));
        factory.putProperty(
            HeapMemoryUtilizationAlert.PROCESS_ID,
            String.valueOf(event.getVirtualMachine().getDetails().getPid()));
        factory.putProperty(
            HeapMemoryUtilizationAlert.COMPONENT_NAME,
            AlertBeanUtils.getGridComponentFullName(event.getVirtualMachine()));
        factory.putProperty(
            HeapMemoryUtilizationAlert.HEAP_UTILIZATION,
            String.valueOf(event.getStatistics().getMemoryHeapUsedPerc()));
        factory.putProperty(
            HeapMemoryUtilizationAlert.MAX_HEAP_IN_BYTES,
            String.valueOf(event.getVirtualMachine().getDetails().getMemoryHeapMaxInBytes()));

        Alert alert = factory.toAlert();
        admin.getAlertManager().triggerAlert(new HeapMemoryUtilizationAlert(alert));
      }
    }
  }
  private void validateProperties() {

    if (config.getHighThresholdPerc() == null) {
      throw new BeanConfigurationException("High threshold property is null");
    }

    if (config.getLowThresholdPerc() == null) {
      throw new BeanConfigurationException("Low threshold property is null");
    }

    if (config.getMeasurementPeriod() == null) {
      throw new BeanConfigurationException("Measurement period property is null");
    }

    if (config.getHighThresholdPerc() < config.getLowThresholdPerc()) {
      throw new BeanConfigurationException(
          "Low threshold ["
              + config.getLowThresholdPerc()
              + "%] must be less than high threshold value ["
              + config.getHighThresholdPerc()
              + "%]");
    }

    if (config.getHighThresholdPerc() < 0) {
      throw new BeanConfigurationException(
          "High threshold [" + config.getHighThresholdPerc() + "%] must greater than zero");
    }

    if (config.getLowThresholdPerc() < 0) {
      throw new BeanConfigurationException(
          "Low threshold [" + config.getLowThresholdPerc() + "%] must greater or equal to zero");
    }

    if (config.getMeasurementPeriod() < StatisticsMonitor.DEFAULT_MONITOR_INTERVAL) {
      throw new BeanConfigurationException(
          "Measurement period ["
              + config.getMeasurementPeriod()
              + " ms] must be greater than ["
              + StatisticsMonitor.DEFAULT_MONITOR_INTERVAL
              + " ms]");
    }
  }