public void reconcileAlertDefinitions(Cluster cluster, boolean updateScriptPaths) throws AmbariException {
      if (null == cluster) {
        return;
      }

      long clusterId = cluster.getClusterId();
      Map<String, ServiceInfo> stackServiceMap = new HashMap<>();
      Map<String, ComponentInfo> stackComponentMap = new HashMap<>();

      // for every service installed in that cluster, get the service MetaInfo
      // and off of that the alert definitions
      List<AlertDefinition> stackDefinitions = new ArrayList<>(50);

      for (Service service : cluster.getServices().values()) {
        ServiceInfo stackService = getService(service.getDesiredStackId().getStackName(),
            service.getDesiredStackId().getStackVersion(), service.getName());

        if (null == stackService) {
          continue;
        }

        stackServiceMap.put(stackService.getName(), stackService);
        List<ComponentInfo> components = stackService.getComponents();
        for (ComponentInfo component : components) {
          stackComponentMap.put(component.getName(), component);
        }

        // get all alerts defined on the stack for each cluster service
        Set<AlertDefinition> serviceDefinitions = getAlertDefinitions(stackService);
        stackDefinitions.addAll(serviceDefinitions);
      }

      List<AlertDefinitionEntity> persist = new ArrayList<>();
      List<AlertDefinitionEntity> entities = alertDefinitionDao.findAll(clusterId);

      // create a map of the entities for fast extraction
      Map<String, AlertDefinitionEntity> mappedEntities = new HashMap<>(100);
      for (AlertDefinitionEntity entity : entities) {
        mappedEntities.put(entity.getDefinitionName(), entity);
      }

      // for each stack definition, see if it exists and compare if it does
      for( AlertDefinition stackDefinition : stackDefinitions ){
        AlertDefinitionEntity entity = mappedEntities.get(stackDefinition.getName());

        // no entity means this is new; create a new entity
        if (null == entity) {
          entity = alertDefinitionFactory.coerce(clusterId, stackDefinition);
          persist.add(entity);
          continue;
        }

        // definitions from the stack that are altered will not be overwritten;
        // use the REST APIs to modify them instead
        AlertDefinition databaseDefinition = alertDefinitionFactory.coerce(entity);
        if (!stackDefinition.deeplyEquals(databaseDefinition)) {
          if (updateScriptPaths) {
            Source databaseSource = databaseDefinition.getSource();
            Source stackSource = stackDefinition.getSource();
            if (databaseSource.getType() == SourceType.SCRIPT && stackSource.getType() == SourceType.SCRIPT) {
              ScriptSource databaseScript = (ScriptSource) databaseSource;
              ScriptSource stackScript = (ScriptSource) stackSource;
              String oldPath = databaseScript.getPath();
              String newPath = stackScript.getPath();
              if (!Objects.equals(oldPath, newPath)) {
                databaseScript.setPath(newPath);
                entity = alertDefinitionFactory.mergeSource(databaseScript, entity);
                persist.add(entity);

                LOG.info("Updating script path for the alert named {} from '{}' to '{}'",
                  stackDefinition.getName(), oldPath, newPath
                );
              }
            }
          } else {
            LOG.debug("The alert named {} has been modified from the stack definition and will not be merged",
              stackDefinition.getName());
          }
        }
      }

      // ambari agent host-only alert definitions
      persist.addAll(getDefinitionsForMerge(ambariServiceAlertDefinitions.getAgentDefinitions(), clusterId, mappedEntities));

      // ambari server host-only alert definitions
      persist.addAll(getDefinitionsForMerge(ambariServiceAlertDefinitions.getServerDefinitions(), clusterId, mappedEntities));

      // persist any new or updated definition
      for (AlertDefinitionEntity entity : persist) {
        LOG.debug("Merging Alert Definition {} into the database", entity.getDefinitionName());
        alertDefinitionDao.createOrUpdate(entity);
      }

      // all definition resolved; publish their registration
      for (AlertDefinitionEntity def : alertDefinitionDao.findAll(cluster.getClusterId())) {
        AlertDefinition realDef = alertDefinitionFactory.coerce(def);
        AlertDefinitionRegistrationEvent event = new AlertDefinitionRegistrationEvent(cluster.getClusterId(), realDef);

        eventPublisher.publish(event);
      }

      // for every definition, determine if the service and the component are
      // still valid; if they are not, disable them - this covers the case
      // with STORM/REST_API where that component was removed from the
      // stack but still exists in the database - we disable the alert to
      // preserve historical references
      List<AlertDefinitionEntity> definitions = alertDefinitionDao.findAllEnabled(clusterId);
      List<AlertDefinitionEntity> definitionsToDisable = new ArrayList<>();

      for (AlertDefinitionEntity definition : definitions) {
        String serviceName = definition.getServiceName();
        String componentName = definition.getComponentName();

        // the AMBARI service is special, skip it here
        if (RootService.AMBARI.name().equals(serviceName)) {
          continue;
        }

        if (!stackServiceMap.containsKey(serviceName)) {

           LOG.info( "The {} service has been marked as deleted for cluster {}, disabling alert {}",
              serviceName, cluster.getClusterName(), definition.getDefinitionName());

          definitionsToDisable.add(definition);
        } else if (null != componentName && !stackComponentMap.containsKey(componentName)) {

          StackId stackId = cluster.getService(serviceName).getDesiredStackId();
          LOG.info( "The {} component {} has been marked as deleted for stack {}, disabling alert {}",
              serviceName, componentName, stackId, definition.getDefinitionName());

          definitionsToDisable.add(definition);
        }
      }

      // disable definitions and fire the event
      for (AlertDefinitionEntity definition : definitionsToDisable) {
        definition.setEnabled(false);
        alertDefinitionDao.merge(definition);
        eventPublisher.publish(new AlertDefinitionDisabledEvent(clusterId, definition.getDefinitionId(),
            definition.getDefinitionName()));
      }
  }
Compares the alert definitions defined on the stack with those in the
database and merges any new or updated definitions. This method will first
determine the services that are installed on each cluster to prevent alert
definitions from undeployed services from being shown.
<p/>
This method will also detect "agent" alert definitions, which are
definitions that should be run on agent hosts but are not associated with a
service.

@param cluster cluster
@param updateScriptPaths whether existing script-based alerts should be updated
       with possibly new paths from the stack definition
ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java