You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ad...@apache.org on 2017/10/03 09:46:21 UTC

[1/2] ambari git commit: AMBARI-21803. Implement STOMP endpoint for alert definitions

Repository: ambari
Updated Branches:
  refs/heads/branch-3.0-perf d632c0161 -> f0def7cec


http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/HostLevelParamsUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/HostLevelParamsUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/HostLevelParamsUpdateEvent.java
index 66ab38e..d68e802 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/HostLevelParamsUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/HostLevelParamsUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -17,7 +17,9 @@
  */
 package org.apache.ambari.server.events;
 
-import java.util.TreeMap;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
 
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
 import org.apache.ambari.server.agent.stomp.dto.HostLevelParamsCluster;
@@ -46,15 +48,15 @@ public class HostLevelParamsUpdateEvent extends AmbariHostUpdateEvent implements
    * Host level parameters by clusters.
    */
   @JsonProperty("clusters")
-  private TreeMap<String, HostLevelParamsCluster> hostLevelParamsClusters = new TreeMap<>();
+  private final Map<String, HostLevelParamsCluster> hostLevelParamsClusters;
 
-  public HostLevelParamsUpdateEvent(TreeMap<String, HostLevelParamsCluster> hostLevelParamsClusters) {
+  public HostLevelParamsUpdateEvent(Map<String, HostLevelParamsCluster> hostLevelParamsClusters) {
     super(Type.HOSTLEVELPARAMS);
     this.hostLevelParamsClusters = hostLevelParamsClusters;
   }
 
   public HostLevelParamsUpdateEvent(String clusterId, HostLevelParamsCluster hostLevelParamsCluster) {
-    this(new TreeMap<String, HostLevelParamsCluster>(){{put(clusterId, hostLevelParamsCluster);}});
+    this(Collections.singletonMap(clusterId, hostLevelParamsCluster));
   }
 
   @Override
@@ -67,14 +69,6 @@ public class HostLevelParamsUpdateEvent extends AmbariHostUpdateEvent implements
     this.hash = hash;
   }
 
-  public TreeMap<String, HostLevelParamsCluster> getHostLevelParamsClusters() {
-    return hostLevelParamsClusters;
-  }
-
-  public void setHostLevelParamsClusters(TreeMap<String, HostLevelParamsCluster> hostLevelParamsClusters) {
-    this.hostLevelParamsClusters = hostLevelParamsClusters;
-  }
-
   public static HostLevelParamsUpdateEvent emptyUpdate() {
     return new HostLevelParamsUpdateEvent(null);
   }
@@ -95,14 +89,12 @@ public class HostLevelParamsUpdateEvent extends AmbariHostUpdateEvent implements
 
     HostLevelParamsUpdateEvent that = (HostLevelParamsUpdateEvent) o;
 
-    if (hostName != null ? !hostName.equals(that.hostName) : that.hostName != null) return false;
-    return hostLevelParamsClusters != null ? hostLevelParamsClusters.equals(that.hostLevelParamsClusters) : that.hostLevelParamsClusters == null;
+    return Objects.equals(hostName, that.hostName) &&
+      Objects.equals(hostLevelParamsClusters, that.hostLevelParamsClusters);
   }
 
   @Override
   public int hashCode() {
-    int result = hostName != null ? hostName.hashCode() : 0;
-    result = 31 * result + (hostLevelParamsClusters != null ? hostLevelParamsClusters.hashCode() : 0);
-    return result;
+    return Objects.hash(hostName, hostLevelParamsClusters);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
index 239b5b8..b515d5a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.events;
 
 import java.util.Map;
+import java.util.SortedMap;
 import java.util.TreeMap;
 
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
@@ -35,7 +36,7 @@ public class MetadataUpdateEvent extends AmbariUpdateEvent implements Hashable {
   /**
    * Id used to send parameters common to all clusters.
    */
-  private final String AMBARI_LEVEL_CLUSTER_ID = "-1";
+  private static final String AMBARI_LEVEL_CLUSTER_ID = "-1";
 
   /**
    * Actual version hash.
@@ -46,15 +47,17 @@ public class MetadataUpdateEvent extends AmbariUpdateEvent implements Hashable {
    * Map of metadatas for each cluster by cluster ids.
    */
   @JsonProperty("clusters")
-  private TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
+  private final SortedMap<String, MetadataCluster> metadataClusters;
+
+  private MetadataUpdateEvent() {
+    super(Type.METADATA);
+    metadataClusters = null;
+  }
 
-  public MetadataUpdateEvent(TreeMap<String, MetadataCluster> metadataClusters, TreeMap<String, String> ambariLevelParams) {
+  public MetadataUpdateEvent(SortedMap<String, MetadataCluster> metadataClusters, SortedMap<String, String> ambariLevelParams) {
     super(Type.METADATA);
     this.metadataClusters = metadataClusters;
     if (ambariLevelParams != null) {
-      if (this.metadataClusters == null) {
-        this.metadataClusters = new TreeMap<>();
-      }
       this.metadataClusters.put(AMBARI_LEVEL_CLUSTER_ID, new MetadataCluster(null, new TreeMap<>(), ambariLevelParams));
     }
   }
@@ -63,21 +66,18 @@ public class MetadataUpdateEvent extends AmbariUpdateEvent implements Hashable {
     return metadataClusters;
   }
 
-  public void setMetadataClusters(TreeMap<String, MetadataCluster> metadataClusters) {
-    this.metadataClusters = metadataClusters;
-  }
-
   @Override
   public String getHash() {
     return hash;
   }
 
+  @Override
   public void setHash(String hash) {
     this.hash = hash;
   }
 
   public static MetadataUpdateEvent emptyUpdate() {
-    return new MetadataUpdateEvent(null, null);
+    return new MetadataUpdateEvent();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
index 0ba4ac2..20160c9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentInstalledEvent.java
@@ -25,20 +25,11 @@ public class ServiceComponentInstalledEvent extends ServiceEvent {
   private final String m_componentName;
   private final String m_hostName;
   private final boolean m_recoveryEnabled;
+  private final boolean masterComponent;
 
-  /**
-   * Constructor.
-   *
-   * @param clusterId
-   * @param stackName
-   * @param stackVersion
-   * @param serviceName
-   * @param componentName
-   * @param hostName
-   */
   public ServiceComponentInstalledEvent(long clusterId, String stackName,
       String stackVersion, String serviceName, String componentName,
-      String hostName, boolean recoveryEnabled) {
+      String hostName, boolean recoveryEnabled, boolean masterComponent) {
     super(AmbariEventType.SERVICE_COMPONENT_INSTALL_SUCCESS, clusterId,
         stackName,
         stackVersion, serviceName);
@@ -46,6 +37,7 @@ public class ServiceComponentInstalledEvent extends ServiceEvent {
     m_componentName = componentName;
     m_hostName = hostName;
     m_recoveryEnabled = recoveryEnabled;
+    this.masterComponent = masterComponent;
   }
 
   public String getComponentName() {
@@ -63,13 +55,14 @@ public class ServiceComponentInstalledEvent extends ServiceEvent {
     return m_recoveryEnabled;
   }
 
-  /**
-   * {@inheritDoc}
-   */
+  public boolean isMasterComponent() {
+    return masterComponent;
+  }
+
   @Override
   public String toString() {
     StringBuilder buffer = new StringBuilder("ServiceComponentInstalledEvent{");
-    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append("clusterId=").append(m_clusterId);
     buffer.append(", stackName=").append(m_stackName);
     buffer.append(", stackVersion=").append(m_stackVersion);
     buffer.append(", serviceName=").append(m_serviceName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
index 8acc401..3e4d6a2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/ServiceComponentUninstalledEvent.java
@@ -27,20 +27,11 @@ public class ServiceComponentUninstalledEvent extends ServiceEvent {
   private final String m_componentName;
   private final String m_hostName;
   private final boolean m_recoveryEnabled;
+  private final boolean masterComponent;
 
-  /**
-   * Constructor.
-   *
-   * @param clusterId
-   * @param stackName
-   * @param stackVersion
-   * @param serviceName
-   * @param componentName
-   * @param hostName
-   */
   public ServiceComponentUninstalledEvent(long clusterId, String stackName,
       String stackVersion, String serviceName, String componentName,
-      String hostName, boolean recoveryEnabled) {
+      String hostName, boolean recoveryEnabled, boolean masterComponent) {
     super(AmbariEventType.SERVICE_COMPONENT_UNINSTALLED_SUCCESS, clusterId,
         stackName,
         stackVersion, serviceName);
@@ -48,6 +39,7 @@ public class ServiceComponentUninstalledEvent extends ServiceEvent {
     m_componentName = componentName;
     m_hostName = hostName;
     m_recoveryEnabled = recoveryEnabled;
+    this.masterComponent = masterComponent;
   }
 
   /**
@@ -71,13 +63,17 @@ public class ServiceComponentUninstalledEvent extends ServiceEvent {
     return m_recoveryEnabled;
   }
 
+  public boolean isMasterComponent() {
+    return masterComponent;
+  }
+
   /**
    * {@inheritDoc}
    */
   @Override
   public String toString() {
     StringBuilder buffer = new StringBuilder("ServiceComponentUninstalledEvent{");
-    buffer.append("cluserId=").append(m_clusterId);
+    buffer.append("clusterId=").append(m_clusterId);
     buffer.append(", stackName=").append(m_stackName);
     buffer.append(", stackVersion=").append(m_stackVersion);
     buffer.append(", serviceName=").append(m_serviceName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyAgentUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyAgentUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyAgentUpdateEvent.java
index 1fa4e6c..477ea6f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyAgentUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyAgentUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -17,7 +17,7 @@
  */
 package org.apache.ambari.server.events;
 
-import java.util.TreeMap;
+import java.util.SortedMap;
 
 import org.apache.ambari.server.agent.stomp.dto.TopologyCluster;
 
@@ -29,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
  */
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class TopologyAgentUpdateEvent extends TopologyUpdateEvent {
-  public TopologyAgentUpdateEvent(TreeMap<String, TopologyCluster> clusters, String hash, EventType eventType) {
+  public TopologyAgentUpdateEvent(SortedMap<String, TopologyCluster> clusters, String hash, EventType eventType) {
     super(Type.AGENT_TOPOLOGY, clusters, hash, eventType);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyUpdateEvent.java
index 1b5b90b..1237e5b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/TopologyUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,6 +18,8 @@
 package org.apache.ambari.server.events;
 
 import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
 import java.util.TreeMap;
 
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
@@ -37,7 +39,7 @@ public class TopologyUpdateEvent extends AmbariUpdateEvent implements Hashable {
    * Map of clusters topologies by cluster ids.
    */
   @JsonProperty("clusters")
-  private TreeMap<String, TopologyCluster> clusters;
+  private final SortedMap<String, TopologyCluster> clusters;
 
   /**
    * Actual version hash.
@@ -48,25 +50,25 @@ public class TopologyUpdateEvent extends AmbariUpdateEvent implements Hashable {
    * Type of update, is used to differ full current topology (CREATE), adding new or update existing topology
    * elements (UPDATE) and removing existing topology elements (DELETE).
    */
-  private EventType eventType;
+  private final EventType eventType;
 
-  public TopologyUpdateEvent(TreeMap<String, TopologyCluster> clusters, EventType eventType) {
+  public TopologyUpdateEvent(SortedMap<String, TopologyCluster> clusters, EventType eventType) {
     this(Type.UI_TOPOLOGY, clusters, null, eventType);
   }
 
-  public TopologyUpdateEvent(Type type, TreeMap<String, TopologyCluster> clusters, String hash, EventType eventType) {
+  public TopologyUpdateEvent(Type type, SortedMap<String, TopologyCluster> clusters, String hash, EventType eventType) {
     super(type);
     this.clusters = clusters;
     this.hash = hash;
     this.eventType = eventType;
   }
 
-  public TreeMap<String, TopologyCluster> getClusters() {
+  public SortedMap<String, TopologyCluster> getClusters() {
     return clusters;
   }
 
   public TopologyUpdateEvent deepCopy() {
-    TreeMap<String, TopologyCluster> copiedClusters = new TreeMap<>();
+    SortedMap<String, TopologyCluster> copiedClusters = new TreeMap<>();
     for (Map.Entry<String, TopologyCluster> topologyClusterEntry : getClusters().entrySet()) {
       copiedClusters.put(topologyClusterEntry.getKey(), topologyClusterEntry.getValue().deepCopyCluster());
     }
@@ -75,18 +77,10 @@ public class TopologyUpdateEvent extends AmbariUpdateEvent implements Hashable {
     return copiedEvent;
   }
 
-  public void setClusters(TreeMap<String, TopologyCluster> clusters) {
-    this.clusters = clusters;
-  }
-
   public EventType getEventType() {
     return eventType;
   }
 
-  public void setEventType(EventType eventType) {
-    this.eventType = eventType;
-  }
-
   public String getHash() {
     return hash;
   }
@@ -112,14 +106,12 @@ public class TopologyUpdateEvent extends AmbariUpdateEvent implements Hashable {
 
     TopologyUpdateEvent that = (TopologyUpdateEvent) o;
 
-    if (clusters != null ? !clusters.equals(that.clusters) : that.clusters != null) return false;
-    return eventType == that.eventType;
+    return Objects.equals(eventType, that.eventType) &&
+      Objects.equals(clusters, that.clusters);
   }
 
   @Override
   public int hashCode() {
-    int result = clusters != null ? clusters.hashCode() : 0;
-    result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
-    return result;
+    return Objects.hash(clusters, eventType);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java
index c0f9027..33f172c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/alerts/AlertReceivedListener.java
@@ -160,8 +160,7 @@ public class AlertReceivedListener {
         clusterId = event.getClusterId();
       }
 
-      AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId,
-        alert.getName());
+      AlertDefinitionEntity definition = m_definitionDao.findByName(clusterId, alert.getName());
 
       if (null == definition) {
         LOG.warn(
@@ -190,6 +189,14 @@ public class AlertReceivedListener {
         continue;
       }
 
+      updateAlertDetails(alert, definition);
+
+      // jobs that were running when a service/component/host was changed
+      // which invalidate the alert should not be reported
+      if (!isValid(alert)) {
+        continue;
+      }
+
       AlertCurrentEntity current;
       AlertState alertState = alert.getState();
 
@@ -371,6 +378,15 @@ public class AlertReceivedListener {
     }
   }
 
+  private void updateAlertDetails(Alert alert, AlertDefinitionEntity definition) {
+    if (alert.getService() == null) {
+      alert.setService(definition.getServiceName());
+    }
+    if (alert.getComponent() == null) {
+      alert.setComponent(definition.getComponentName());
+    }
+  }
+
   private MaintenanceState getMaintenanceState(Alert alert, Long clusterId) {
     MaintenanceState maintenanceState = MaintenanceState.OFF;
     try {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/requests/StateUpdateListener.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/requests/StateUpdateListener.java b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/requests/StateUpdateListener.java
index 27af717..548ea41 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/requests/StateUpdateListener.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/listeners/requests/StateUpdateListener.java
@@ -1,5 +1,4 @@
-
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -55,16 +54,17 @@ public class StateUpdateListener {
   @Subscribe
   @AllowConcurrentEvents
   public void onUpdateEvent(AmbariUpdateEvent event) throws HostNotRegisteredException {
+    String destination = event.getDestination();
     if (event instanceof AmbariHostUpdateEvent) {
-      AmbariHostUpdateEvent ambariHostUpdateEvent = (AmbariHostUpdateEvent) event;
-      String sessionId = agentSessionManager.getSessionId(ambariHostUpdateEvent.getHostName());
-      LOG.debug("Received status update event {} for host ()", ambariHostUpdateEvent.toString(),
-          ambariHostUpdateEvent.getHostName());
-      simpMessagingTemplate.convertAndSendToUser(sessionId, ambariHostUpdateEvent.getDestination(),
-          ambariHostUpdateEvent, createHeaders(sessionId));
+      AmbariHostUpdateEvent hostUpdateEvent = (AmbariHostUpdateEvent) event;
+      String hostName = hostUpdateEvent.getHostName();
+      String sessionId = agentSessionManager.getSessionId(hostName);
+      LOG.debug("Received status update event {} for host {} registered with session ID {}", hostUpdateEvent, hostName, sessionId);
+      MessageHeaders headers = createHeaders(sessionId);
+      simpMessagingTemplate.convertAndSendToUser(sessionId, destination, event, headers);
     } else {
-      LOG.debug("Received status update event {}", event.toString());
-      simpMessagingTemplate.convertAndSend(event.getDestination(), event);
+      LOG.debug("Received status update event {}", event);
+      simpMessagingTemplate.convertAndSend(destination, event);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index 9473cfc..3ca9d3a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -30,10 +30,7 @@ import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvi
 import org.apache.ambari.server.events.AlertDefinitionChangedEvent;
 import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
 import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
-import org.apache.ambari.server.events.AlertDefinitionUpdateHolder;
-import org.apache.ambari.server.events.AlertDefinitionsUpdateEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
@@ -102,12 +99,6 @@ public class AlertDefinitionDAO {
   @Inject
   private AlertDefinitionFactory alertDefinitionFactory;
 
-  @Inject
-  private AlertDefinitionUpdateHolder alertDefinitionUpdateHolder;
-
-  @Inject
-  private StateUpdateEventPublisher stateUpdateEventPublisher;
-
   /**
    * Gets an alert definition with the specified ID.
    *
@@ -349,10 +340,6 @@ public class AlertDefinitionDAO {
     if (null != coerced) {
       AlertDefinitionRegistrationEvent event = new AlertDefinitionRegistrationEvent(
           alertDefinition.getClusterId(), coerced);
-
-      stateUpdateEventPublisher.publish(new AlertDefinitionsUpdateEvent(coerced,
-          alertDefinition.getRepeatTolerance(), Boolean.valueOf(alertDefinition.isRepeatToleranceEnabled())));
-
       eventPublisher.publish(event);
     } else {
       LOG.warn("Unable to broadcast alert registration event for {}",
@@ -392,9 +379,6 @@ public class AlertDefinitionDAO {
 
     eventPublisher.publish(event);
 
-    alertDefinitionUpdateHolder.updateIfNeeded(new AlertDefinitionsUpdateEvent(definition,
-        alertDefinition.getRepeatTolerance(), Boolean.valueOf(alertDefinition.isRepeatToleranceEnabled())));
-
     return entity;
   }
 
@@ -441,8 +425,6 @@ public class AlertDefinitionDAO {
                 alertDefinition.getClusterId(), coerced);
 
         eventPublisher.publish(event);
-
-        stateUpdateEventPublisher.publish(new AlertDefinitionsUpdateEvent(alertDefinition.getDefinitionId()));
       } else {
         LOG.warn("Unable to broadcast alert removal event for {}",
                 alertDefinition.getDefinitionName());

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java
index 64c983f..12577f9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AggregateSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -27,6 +31,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class AggregateSource extends Source {
 
   @SerializedName("alert_name")
@@ -35,6 +40,7 @@ public class AggregateSource extends Source {
   /**
    * @return the unique name of the alert that will have its values aggregated.
    */
+  @JsonProperty("alert_name")
   public String getAlertName() {
     return m_alertName;
   }
@@ -47,23 +53,11 @@ public class AggregateSource extends Source {
     m_alertName = alertName;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-
-    result = prime * result
-        + ((m_alertName == null) ? 0 : m_alertName.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), m_alertName);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -79,14 +73,6 @@ public class AggregateSource extends Source {
     }
 
     AggregateSource other = (AggregateSource) obj;
-    if (m_alertName == null) {
-      if (other.m_alertName != null) {
-        return false;
-      }
-    } else if (!m_alertName.equals(other.m_alertName)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(m_alertName, other.m_alertName);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
index 665430d..a872257 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinition.java
@@ -21,6 +21,8 @@ import java.util.HashSet;
 
 import org.apache.commons.lang.StringUtils;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -36,6 +38,7 @@ import com.google.gson.annotations.SerializedName;
  * When making comparisons for equality for things like stack/database merging,
  * use {@link #deeplyEquals(Object)}.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class AlertDefinition {
 
   private long clusterId;
@@ -175,6 +178,7 @@ public class AlertDefinition {
   /**
    * @return {@code true} if the host is ignored.
    */
+  @JsonProperty("ignore_host")
   public boolean isHostIgnored() {
     return ignoreHost;
   }
@@ -210,6 +214,7 @@ public class AlertDefinition {
   /**
    * @return the help url for this definition or {@code null} if none.
    */
+  @JsonProperty("help_url")
   public String getHelpURL() {
     return helpURL;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
index 8dd78cf..52ea614 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
@@ -22,6 +22,7 @@ import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -31,6 +32,8 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
@@ -52,6 +55,7 @@ import org.apache.commons.codec.binary.Hex;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -230,23 +234,26 @@ public class AlertDefinitionHash {
    * @return the alert definitions for the host, or an empty set (never
    *         {@code null}).
    */
-  public List<AlertDefinition> getAlertDefinitions(
-      String clusterName,
-      String hostName) {
-
-    Set<AlertDefinitionEntity> entities = getAlertDefinitionEntities(
-        clusterName, hostName);
-
-    List<AlertDefinition> definitions = new ArrayList<>(
-      entities.size());
+  public List<AlertDefinition> getAlertDefinitions(String clusterName, String hostName) {
+    return coerce(getAlertDefinitionEntities(clusterName, hostName));
+  }
 
-    for (AlertDefinitionEntity entity : entities) {
-      definitions.add(m_factory.coerce(entity));
+  public Map<Long, Map<Long, AlertDefinition>> getAlertDefinitions(String hostName) throws AmbariException {
+    Map<Long, Map<Long, AlertDefinition>> result = new HashMap<>();
+    for (Cluster cluster : m_clusters.get().getClustersForHost(hostName)) {
+      List<AlertDefinition> alertDefinitions = getAlertDefinitions(cluster.getClusterName(), hostName);
+      result.put(cluster.getClusterId(), mapById(alertDefinitions));
     }
+    return result;
+  }
 
-    return definitions;
+  public Map<Long, AlertDefinition> findByServiceComponent(long clusterId, String serviceName, String componentName) {
+    return mapById(coerce(m_definitionDao.findByServiceComponent(clusterId, serviceName, componentName)));
   }
 
+  public Map<Long, AlertDefinition> findByServiceMaster(long clusterId, String... serviceName) {
+    return mapById(coerce(m_definitionDao.findByServiceMaster(clusterId, Sets.newHashSet(serviceName))));
+  }
 
   /**
    * Invalidate the hashes of any host that would be affected by the specified
@@ -635,8 +642,6 @@ public class AlertDefinitionHash {
     try {
       Cluster cluster = m_clusters.get().getCluster(clusterName);
       if (null == cluster) {
-
-
         return Collections.emptySet();
       }
 
@@ -650,8 +655,7 @@ public class AlertDefinitionHash {
           String componentName = serviceComponent.getServiceComponentName();
 
           // add all alerts for this service/component pair
-          definitions.addAll(m_definitionDao.findByServiceComponent(clusterId,
-              serviceName, componentName));
+          definitions.addAll(m_definitionDao.findByServiceComponent(clusterId, serviceName, componentName));
         }
 
         // for every service, get the master components and see if the host
@@ -693,4 +697,16 @@ public class AlertDefinitionHash {
 
     return definitions;
   }
+
+  private List<AlertDefinition> coerce(Collection<AlertDefinitionEntity> entities) {
+    return entities.stream()
+      .map(m_factory::coerce)
+      .collect(Collectors.toList());
+  }
+
+  private static Map<Long, AlertDefinition> mapById(Collection<AlertDefinition> definitions) {
+    return definitions.stream()
+      .collect(Collectors.toMap(AlertDefinition::getDefinitionId, Function.identity()));
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
index 7b0107b..6a89da5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
@@ -19,6 +19,8 @@ package org.apache.ambari.server.state.alert;
 
 import java.util.Set;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -29,6 +31,7 @@ import com.google.gson.annotations.SerializedName;
  * can be swapped out in other source types where a plain string is used for the
  * URI.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class AlertUri {
   /**
    * The HTTP URI to use.
@@ -85,6 +88,7 @@ public class AlertUri {
    * An optional timeout value for connections.
    */
   @SerializedName("connection_timeout")
+  @JsonProperty("connection_timeout")
   private float m_connectionTimeout = 5.0f;
 
   /**
@@ -102,6 +106,7 @@ public class AlertUri {
    *
    * @return the httpUri the URI (or {@code null} to always use the secure URL).
    */
+  @JsonProperty("http")
   public String getHttpUri() {
     return m_httpUri;
   }
@@ -123,6 +128,7 @@ public class AlertUri {
    *
    * @return the default port if none of the http properties are found.
    */
+  @JsonProperty("default_port")
   public Number getDefaultPort() {
     return m_port;
   }
@@ -133,6 +139,7 @@ public class AlertUri {
    * @return the httpsUri the URI (or {@code null} to always use the insecure
    *         URL).
    */
+  @JsonProperty("https")
   public String getHttpsUri() {
     return m_httpsUri;
   }
@@ -144,6 +151,7 @@ public class AlertUri {
    * @return the httpsProperty the configuration property, or {@code null} for
    *         none.
    */
+  @JsonProperty("https_property")
   public String getHttpsProperty() {
     return m_httpsProperty;
   }
@@ -155,6 +163,7 @@ public class AlertUri {
    * @return the httpsPropertyValue the literal value that indicates SSL mode is
    *         enabled, or {@code null} for none.
    */
+  @JsonProperty("https_property_value")
   public String getHttpsPropertyValue() {
     return m_httpsPropertyValue;
   }
@@ -164,6 +173,7 @@ public class AlertUri {
    *
    * @return the configuration property, or {@code null} for none.
    */
+  @JsonProperty("kerberos_keytab")
   public String getKerberosKeytab() {
     return m_kerberosKeytab;
   }
@@ -173,6 +183,7 @@ public class AlertUri {
    *
    * @return the configuration property, or {@code null} for none.
    */
+  @JsonProperty("kerberos_principal")
   public String getKerberosPrincipal() {
     return m_kerberosPrincipal;
   }
@@ -184,6 +195,7 @@ public class AlertUri {
    * @return the HA structure or {@code null} if the component does not support
    *         HA mode.
    */
+  @JsonProperty("high_availability")
   public HighAvailability getHighAvailability() {
     return m_highAvailability;
   }
@@ -244,6 +256,7 @@ public class AlertUri {
      *
      * @return the nameservice
      */
+    @JsonProperty("nameservice")
     public String getNameservice() {
       return m_nameservice;
     }
@@ -253,6 +266,7 @@ public class AlertUri {
      *
      * @return the alias key
      */
+    @JsonProperty("alias_key")
     public String getAliasKey() {
       return m_aliasKey;
     }
@@ -262,6 +276,7 @@ public class AlertUri {
      *
      * @return the httpPattern
      */
+    @JsonProperty("http_pattern")
     public String getHttpPattern() {
       return m_httpPattern;
     }
@@ -271,6 +286,7 @@ public class AlertUri {
      *
      * @return the httpsPattern
      */
+    @JsonProperty("https_pattern")
     public String getHttpsPattern() {
       return m_httpsPattern;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AmsSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AmsSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AmsSource.java
index d586f81..f894be1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AmsSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AmsSource.java
@@ -18,7 +18,10 @@
 package org.apache.ambari.server.state.alert;
 
 import java.util.List;
+import java.util.Objects;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -27,6 +30,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class AmsSource extends Source {
 
   @SerializedName("uri")
@@ -38,6 +42,7 @@ public class AmsSource extends Source {
   /**
    * @return the ams info, if this metric is ams-based
    */
+  @JsonProperty("ams")
   public AmsInfo getAmsInfo() {
     return amsInfo;
   }
@@ -45,26 +50,16 @@ public class AmsSource extends Source {
   /**
    * @return the uri info, which may include port information
    */
+  @JsonProperty("uri")
   public AlertUri getUri() {
     return uri;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
-    result = prime * result + ((amsInfo == null) ? 0 : amsInfo.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), uri, amsInfo);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -80,29 +75,14 @@ public class AmsSource extends Source {
     }
 
     AmsSource other = (AmsSource) obj;
-
-    if (uri == null) {
-      if (other.uri != null) {
-        return false;
-      }
-    } else if (!uri.equals(other.uri)) {
-      return false;
-    }
-
-    if (amsInfo == null) {
-      if (other.amsInfo != null) {
-        return false;
-      }
-    } else if (!amsInfo.equals(other.amsInfo)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(uri, other.uri) &&
+      Objects.equals(amsInfo, other.amsInfo);
   }
 
   /**
    * Represents the {@code ams} element in a Metric alert.
    */
+  @JsonInclude(JsonInclude.Include.NON_EMPTY)
   public static class AmsInfo {
 
     @SerializedName("metric_list")
@@ -120,6 +100,7 @@ public class AmsSource extends Source {
     @SerializedName("minimum_value")
     private int minimumValue;
 
+    @JsonProperty("app_id")
     public String getAppId() {
       return appId;
     }
@@ -132,6 +113,7 @@ public class AmsSource extends Source {
       return compute;
     }
 
+    @JsonProperty("metric_list")
     public List<String> getMetricList() {
       return metricList;
     }
@@ -140,6 +122,7 @@ public class AmsSource extends Source {
       return value;
     }
 
+    @JsonProperty("minimum_value")
     public int getMinimumValue() {
       return minimumValue;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
index 11eee05..35a0261 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/MetricSource.java
@@ -19,7 +19,10 @@ package org.apache.ambari.server.state.alert;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -28,6 +31,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class MetricSource extends Source {
 
   @SerializedName("uri")
@@ -42,6 +46,7 @@ public class MetricSource extends Source {
   /**
    * @return the jmx info, if this metric is jmx-based
    */
+  @JsonProperty("jmx")
   public JmxInfo getJmxInfo() {
     return jmxInfo;
   }
@@ -49,6 +54,7 @@ public class MetricSource extends Source {
   /**
    * @return the ganglia info, if this metric is ganglia-based
    */
+  @JsonProperty("ganglia")
   public String getGangliaInfo() {
     return gangliaInfo;
   }
@@ -56,28 +62,16 @@ public class MetricSource extends Source {
   /**
    * @return the uri info, which may include port information
    */
+  @JsonProperty("uri")
   public AlertUri getUri() {
     return uri;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result
-        + ((gangliaInfo == null) ? 0 : gangliaInfo.hashCode());
-    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
-    result = prime * result + ((jmxInfo == null) ? 0 : jmxInfo.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), gangliaInfo, uri, jmxInfo);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -93,42 +87,22 @@ public class MetricSource extends Source {
     }
 
     MetricSource other = (MetricSource) obj;
-    if (gangliaInfo == null) {
-      if (other.gangliaInfo != null) {
-        return false;
-      }
-    } else if (!gangliaInfo.equals(other.gangliaInfo)) {
-      return false;
-    }
-
-    if (uri == null) {
-      if (other.uri != null) {
-        return false;
-      }
-    } else if (!uri.equals(other.uri)) {
-      return false;
-    }
-
-    if (jmxInfo == null) {
-      if (other.jmxInfo != null) {
-        return false;
-      }
-    } else if (!jmxInfo.equals(other.jmxInfo)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(gangliaInfo, other.gangliaInfo) &&
+      Objects.equals(uri, other.uri) &&
+      Objects.equals(jmxInfo, other.jmxInfo);
   }
 
   /**
    * Represents the {@code jmx} element in a Metric alert.
    */
+  @JsonInclude(JsonInclude.Include.NON_EMPTY)
   public static class JmxInfo {
     @SerializedName("property_list")
     private List<String> propertyList;
 
     private String value;
 
+    @JsonProperty("property_list")
     public List<String> getPropertyList() {
       return propertyList;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ParameterizedSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ParameterizedSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ParameterizedSource.java
index 8ae8d1f..2714ca4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ParameterizedSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ParameterizedSource.java
@@ -19,11 +19,14 @@ package org.apache.ambari.server.state.alert;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 import org.apache.ambari.server.state.AlertState;
 import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 
@@ -32,6 +35,7 @@ import com.google.gson.annotations.SerializedName;
  * computing the {@link AlertState} is dependant on user-specified parameters.
  * For example, the parameters might be threshold values.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public abstract class ParameterizedSource extends Source {
 
   /**
@@ -46,6 +50,7 @@ public abstract class ParameterizedSource extends Source {
    *
    * @return the list of parameters, or an empty list if none.
    */
+  @JsonProperty("parameters")
   public List<AlertParameter> getParameters() {
     if (null == m_parameters) {
       return Collections.emptyList();
@@ -58,6 +63,7 @@ public abstract class ParameterizedSource extends Source {
    * The {@link AlertParameter} class represents a single parameter that can be
    * passed into an alert which takes parameters.
    */
+  @JsonInclude(JsonInclude.Include.NON_EMPTY)
   public static class AlertParameter {
     @SerializedName("name")
     private String m_name;
@@ -92,6 +98,7 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the name
      */
+    @JsonProperty("name")
     public String getName() {
       return m_name;
     }
@@ -101,6 +108,7 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the displayName
      */
+    @JsonProperty("display_name")
     public String getDisplayName() {
       return m_displayName;
     }
@@ -110,6 +118,7 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the units
      */
+    @JsonProperty("units")
     public String getUnits() {
       return m_units;
     }
@@ -119,6 +128,7 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the value
      */
+    @JsonProperty("value")
     public Object getValue() {
       return m_value;
     }
@@ -128,15 +138,22 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the description
      */
+    @JsonProperty("description")
     public String getDescription() {
       return m_description;
     }
 
+    @JsonProperty("type")
+    public AlertParameterType getType() {
+      return m_type;
+    }
+
     /**
      * Gets the visibility of the parameter.
      *
      * @return the visibility
      */
+    @JsonProperty("visibility")
     public AlertParameterVisibility getVisibility() {
       return m_visibility;
     }
@@ -147,92 +164,34 @@ public abstract class ParameterizedSource extends Source {
      *
      * @return the threshold, or {@code null}.
      */
+    @JsonProperty("threshold")
     public AlertState getThreshold() {
       return m_threshold;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((m_description == null) ? 0 : m_description.hashCode());
-      result = prime * result + ((m_displayName == null) ? 0 : m_displayName.hashCode());
-      result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
-      result = prime * result + ((m_threshold == null) ? 0 : m_threshold.hashCode());
-      result = prime * result + ((m_type == null) ? 0 : m_type.hashCode());
-      result = prime * result + ((m_units == null) ? 0 : m_units.hashCode());
-      result = prime * result + ((m_value == null) ? 0 : m_value.hashCode());
-      result = prime * result + ((m_visibility == null) ? 0 : m_visibility.hashCode());
-      return result;
+      return Objects.hash(m_description, m_displayName, m_name, m_threshold, m_type, m_units, m_value, m_visibility);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean equals(Object obj) {
       if (this == obj) {
         return true;
       }
-      if (obj == null) {
-        return false;
-      }
-      if (getClass() != obj.getClass()) {
+      if (obj == null || getClass() != obj.getClass()) {
         return false;
       }
+
       AlertParameter other = (AlertParameter) obj;
-      if (m_description == null) {
-        if (other.m_description != null) {
-          return false;
-        }
-      } else if (!m_description.equals(other.m_description)) {
-        return false;
-      }
-      if (m_displayName == null) {
-        if (other.m_displayName != null) {
-          return false;
-        }
-      } else if (!m_displayName.equals(other.m_displayName)) {
-        return false;
-      }
-      if (m_name == null) {
-        if (other.m_name != null) {
-          return false;
-        }
-      } else if (!m_name.equals(other.m_name)) {
-        return false;
-      }
-      if (m_threshold != other.m_threshold) {
-        return false;
-      }
-      if (m_type != other.m_type) {
-        return false;
-      }
-      if (m_units == null) {
-        if (other.m_units != null) {
-          return false;
-        }
-      } else if (!m_units.equals(other.m_units)) {
-        return false;
-      }
-      if (m_value == null) {
-        if (other.m_value != null) {
-          return false;
-        }
-      } else if (!m_value.equals(other.m_value)) {
-        return false;
-      }
-      if (m_visibility == null) {
-        if (other.m_visibility != null) {
-          return false;
-        }
-      } else if (!m_visibility.equals(other.m_visibility)) {
-        return false;
-      }
-      return true;
+      return Objects.equals(m_description, other.m_description) &&
+        Objects.equals(m_displayName, other.m_displayName) &&
+        Objects.equals(m_name, other.m_name) &&
+        Objects.equals(m_threshold, other.m_threshold) &&
+        Objects.equals(m_type, other.m_type) &&
+        Objects.equals(m_units, other.m_units) &&
+        Objects.equals(m_value, other.m_value) &&
+        Objects.equals(m_visibility, other.m_visibility);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java
index 927d893..8008190 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PercentSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -25,6 +29,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class PercentSource extends Source {
 
   @SerializedName("numerator")
@@ -38,6 +43,7 @@ public class PercentSource extends Source {
    *
    * @return a metric value representing the numerator (never {@code null}).
    */
+  @JsonProperty("numerator")
   public MetricFractionPart getNumerator() {
     return m_numerator;
   }
@@ -47,29 +53,16 @@ public class PercentSource extends Source {
    *
    * @return a metric value representing the denominator (never {@code null}).
    */
+  @JsonProperty("denominator")
   public MetricFractionPart getDenominator() {
     return m_denominator;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-
-    int result = super.hashCode();
-    result = prime * result
-        + ((m_denominator == null) ? 0 : m_denominator.hashCode());
-    result = prime * result
-        + ((m_numerator == null) ? 0 : m_numerator.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), m_denominator, m_numerator);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -85,24 +78,8 @@ public class PercentSource extends Source {
     }
 
     PercentSource other = (PercentSource) obj;
-
-    if (m_denominator == null) {
-      if (other.m_denominator != null) {
-        return false;
-      }
-    } else if (!m_denominator.equals(other.m_denominator)) {
-      return false;
-    }
-
-    if (m_numerator == null) {
-      if (other.m_numerator != null) {
-        return false;
-      }
-    } else if (!m_numerator.equals(other.m_numerator)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(m_denominator, other.m_denominator) &&
+      Objects.equals(m_numerator, other.m_numerator);
   }
 
   /**
@@ -112,6 +89,7 @@ public class PercentSource extends Source {
    * Equality checking for instances of this class should be executed on every
    * member to ensure that reconciling stack differences is correct.
    */
+  @JsonInclude(JsonInclude.Include.NON_EMPTY)
   public static final class MetricFractionPart {
     @SerializedName("jmx")
     private String m_jmxInfo = null;
@@ -122,6 +100,7 @@ public class PercentSource extends Source {
     /**
      * @return the jmx info, if this metric is jmx-based
      */
+    @JsonProperty("jmx")
     public String getJmxInfo() {
       return m_jmxInfo;
     }
@@ -129,62 +108,29 @@ public class PercentSource extends Source {
     /**
      * @return the ganglia info, if this metric is ganglia-based
      */
+    @JsonProperty("ganglia")
     public String getGangliaInfo() {
       return m_gangliaInfo;
     }
 
-    /**
-     *
-     */
     @Override
     public int hashCode() {
-      final int prime = 31;
-
-      int result = 1;
-      result = prime * result
-          + ((m_gangliaInfo == null) ? 0 : m_gangliaInfo.hashCode());
-
-      result = prime * result
-          + ((m_jmxInfo == null) ? 0 : m_jmxInfo.hashCode());
-
-      return result;
+      return Objects.hash(m_gangliaInfo, m_jmxInfo);
     }
 
-    /**
-     *
-     */
     @Override
     public boolean equals(Object obj) {
       if (this == obj) {
         return true;
       }
 
-      if (obj == null) {
-        return false;
-      }
-
-      if (getClass() != obj.getClass()) {
+      if (obj == null || getClass() != obj.getClass()) {
         return false;
       }
 
       MetricFractionPart other = (MetricFractionPart) obj;
-      if (m_gangliaInfo == null) {
-        if (other.m_gangliaInfo != null) {
-          return false;
-        }
-      } else if (!m_gangliaInfo.equals(other.m_gangliaInfo)) {
-        return false;
-      }
-
-      if (m_jmxInfo == null) {
-        if (other.m_jmxInfo != null) {
-          return false;
-        }
-      } else if (!m_jmxInfo.equals(other.m_jmxInfo)) {
-        return false;
-      }
-
-      return true;
+      return Objects.equals(m_gangliaInfo, other.m_gangliaInfo) &&
+        Objects.equals(m_jmxInfo, other.m_jmxInfo);
     }
 
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java
index 7b89382..ef833f3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/PortSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -25,6 +29,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class PortSource extends ParameterizedSource {
 
   @SerializedName("uri")
@@ -36,6 +41,7 @@ public class PortSource extends ParameterizedSource {
   /**
    * @return the URI to check for a valid port
    */
+  @JsonProperty("uri")
   public String getUri() {
     return m_uri;
   }
@@ -51,6 +57,7 @@ public class PortSource extends ParameterizedSource {
   /**
    * @return the port to check on the given URI.
    */
+  @JsonProperty("default_port")
   public int getPort() {
     return m_port;
   }
@@ -63,22 +70,11 @@ public class PortSource extends ParameterizedSource {
     m_port = port;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result + m_port;
-    result = prime * result + ((m_uri == null) ? 0 : m_uri.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), m_port, m_uri);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -94,20 +90,8 @@ public class PortSource extends ParameterizedSource {
     }
 
     PortSource other = (PortSource) obj;
-
-    if (m_port != other.m_port) {
-      return false;
-    }
-
-    if (m_uri == null) {
-      if (other.m_uri != null) {
-        return false;
-      }
-    } else if (!m_uri.equals(other.m_uri)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(m_port, other.m_port) &&
+      Objects.equals(m_uri, other.m_uri);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java
index dc03e2f..304e5da 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Reporting.java
@@ -17,7 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -27,6 +30,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class Reporting {
 
   /**
@@ -60,6 +64,7 @@ public class Reporting {
   /**
    * @return the WARNING structure or {@code null} if none.
    */
+  @JsonProperty("warning")
   public ReportTemplate getWarning() {
     return m_warning;
   }
@@ -75,6 +80,7 @@ public class Reporting {
   /**
    * @return the CRITICAL structure or {@code null} if none.
    */
+  @JsonProperty("critical")
   public ReportTemplate getCritical() {
     return m_critical;
   }
@@ -90,6 +96,7 @@ public class Reporting {
   /**
    * @return the OK structure or {@code null} if none.
    */
+  @JsonProperty("ok")
   public ReportTemplate getOk() {
     return m_ok;
   }
@@ -108,6 +115,7 @@ public class Reporting {
    *
    * @return the units, or {@code null} for none.
    */
+  @JsonProperty("units")
   public String getUnits() {
     return m_units;
   }
@@ -123,6 +131,7 @@ public class Reporting {
     m_units = units;
   }
 
+  @JsonProperty("type")
   public ReportingType getType() {
     return m_type;
   }
@@ -131,73 +140,26 @@ public class Reporting {
     this.m_type = m_type;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-
-    int result = 1;
-    result = prime * result
-        + ((m_critical == null) ? 0 : m_critical.hashCode());
-    result = prime * result + ((m_ok == null) ? 0 : m_ok.hashCode());
-    result = prime * result + ((m_warning == null) ? 0 : m_warning.hashCode());
-    result = prime * result + ((m_type == null) ? 0 : m_type.hashCode());
-    return result;
+    return Objects.hash(m_critical, m_ok, m_warning, m_type);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
       return true;
     }
 
-    if (obj == null) {
-      return false;
-    }
-
-    if (getClass() != obj.getClass()) {
+    if (obj == null || getClass() != obj.getClass()) {
       return false;
     }
 
     Reporting other = (Reporting) obj;
-    if (m_critical == null) {
-      if (other.m_critical != null) {
-        return false;
-      }
-    } else if (!m_critical.equals(other.m_critical)) {
-      return false;
-    }
-
-    if (m_ok == null) {
-      if (other.m_ok != null) {
-        return false;
-      }
-    } else if (!m_ok.equals(other.m_ok)) {
-      return false;
-    }
-
-    if (m_warning == null) {
-      if (other.m_warning != null) {
-        return false;
-      }
-    } else if (!m_warning.equals(other.m_warning)) {
-      return false;
-    }
-
-    if (m_type == null) {
-      if (other.m_type != null) {
-        return false;
-      }
-    } else if (!m_type.equals(other.m_type)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(m_critical, other.m_critical) &&
+      Objects.equals(m_ok, other.m_ok) &&
+      Objects.equals(m_warning, other.m_warning) &&
+      Objects.equals(m_type, other.m_type);
   }
 
   /**
@@ -218,6 +180,7 @@ public class Reporting {
     /**
      * @return the parameterized text of this template or {@code null} if none.
      */
+    @JsonProperty("text")
     public String getText() {
       return m_text;
     }
@@ -233,6 +196,7 @@ public class Reporting {
     /**
      * @return the threshold value for this template or {@code null} if none.
      */
+    @JsonProperty("value")
     public Double getValue() {
       return m_value;
     }
@@ -245,53 +209,24 @@ public class Reporting {
       m_value = value;
     }
 
-    /**
-     *
-     */
     @Override
     public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((m_text == null) ? 0 : m_text.hashCode());
-      result = prime * result + ((m_value == null) ? 0 : m_value.hashCode());
-      return result;
+      return Objects.hash(m_text, m_value);
     }
 
-    /**
-     *
-     */
     @Override
     public boolean equals(Object obj) {
       if (this == obj) {
         return true;
       }
 
-      if (obj == null) {
-        return false;
-      }
-
-      if (getClass() != obj.getClass()) {
+      if (obj == null || getClass() != obj.getClass()) {
         return false;
       }
 
       ReportTemplate other = (ReportTemplate) obj;
-
-      if (m_text == null) {
-        if (other.m_text != null) {
-          return false;
-        }
-      } else if (!m_text.equals(other.m_text)) {
-        return false;
-      }
-
-      if (m_value == null) {
-        if (other.m_value != null) {
-          return false;
-        }
-      } else if (!m_value.equals(other.m_value)) {
-        return false;
-      }
-      return true;
+      return Objects.equals(m_text, other.m_text) &&
+        Objects.equals(m_value, other.m_value);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java
index a5ed440..bc6c367 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ScriptSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -25,6 +29,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class ScriptSource extends ParameterizedSource {
 
   @SerializedName("path")
@@ -33,25 +38,16 @@ public class ScriptSource extends ParameterizedSource {
   /**
    * @return the path to the script file.
    */
+  @JsonProperty("path")
   public String getPath() {
     return m_path;
   }
 
-  /**
-   * {@inheritDoc}
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result + ((m_path == null) ? 0 : m_path.hashCode());
-
-    return result;
+    return Objects.hash(super.hashCode(), m_path);
   }
 
-  /**
-   * {@inheritDoc}
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -67,15 +63,6 @@ public class ScriptSource extends ParameterizedSource {
     }
 
     ScriptSource other = (ScriptSource) obj;
-
-    if (m_path == null) {
-      if (other.m_path != null) {
-        return false;
-      }
-    } else if (!m_path.equals(other.m_path)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(m_path, other.m_path);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ServerSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ServerSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ServerSource.java
index c58867a..f544d9a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ServerSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/ServerSource.java
@@ -17,12 +17,17 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 
 /**
  * Alert when the source type is defined as {@link SourceType#SERVER}
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class ServerSource extends ParameterizedSource {
 
   @SerializedName("class")
@@ -31,6 +36,7 @@ public class ServerSource extends ParameterizedSource {
   /**
    * Gets the fully qualified classname specified in the source.
    */
+  @JsonProperty("class")
   public String getSourceClass() {
     return m_class;
   }
@@ -40,10 +46,7 @@ public class ServerSource extends ParameterizedSource {
    */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result + ((m_class == null) ? 0 : m_class.hashCode());
-    return result;
+    return Objects.hash(super.hashCode(), m_class);
   }
 
   /**
@@ -64,14 +67,7 @@ public class ServerSource extends ParameterizedSource {
     }
 
     ServerSource other = (ServerSource) obj;
-    if (m_class == null) {
-      if (other.m_class != null) {
-        return false;
-      }
-    } else if (!m_class.equals(other.m_class)) {
-      return false;
-    }
-    return true;
+    return Objects.equals(m_class, other.m_class);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java
index aa841d5..176fb1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/Source.java
@@ -17,7 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -49,9 +52,7 @@ public abstract class Source {
     this.type = type;
   }
 
-  /**
-   * @return
-   */
+  @JsonProperty("reporting")
   public Reporting getReporting() {
     return reporting;
   }
@@ -66,48 +67,23 @@ public abstract class Source {
     this.reporting = reporting;
   }
 
-  /**
-   *
-   */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + ((reporting == null) ? 0 : reporting.hashCode());
-    result = prime * result + ((type == null) ? 0 : type.hashCode());
-
-    return result;
+    return Objects.hash(reporting, type);
   }
 
-  /**
-   *
-   */
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
       return true;
     }
 
-    if (obj == null) {
-      return false;
-    }
-
-    if (getClass() != obj.getClass()) {
+    if (obj == null || getClass() != obj.getClass()) {
       return false;
     }
 
     Source other = (Source) obj;
-    if (reporting == null) {
-      if (other.reporting != null) {
-        return false;
-      }
-    } else if (!reporting.equals(other.reporting)) {
-      return false;
-    }
-
-    if (type != other.type) {
-      return false;
-    }
-    return true;
+    return Objects.equals(reporting, other.reporting) &&
+      Objects.equals(type, other.type);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/alert/WebSource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/WebSource.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/WebSource.java
index ef94604..63b5647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/WebSource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/WebSource.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.state.alert;
 
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -25,6 +29,7 @@ import com.google.gson.annotations.SerializedName;
  * Equality checking for instances of this class should be executed on every
  * member to ensure that reconciling stack differences is correct.
  */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class WebSource extends Source {
 
   @SerializedName("uri")
@@ -33,6 +38,7 @@ public class WebSource extends Source {
   /**
    * @return the uri info, which may include port information
    */
+  @JsonProperty("uri")
   public AlertUri getUri() {
     return uri;
   }
@@ -42,10 +48,7 @@ public class WebSource extends Source {
    */
   @Override
   public int hashCode() {
-    final int prime = 31;
-    int result = super.hashCode();
-    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
-    return result;
+    return Objects.hash(super.hashCode(), uri);
   }
 
   /**
@@ -66,14 +69,6 @@ public class WebSource extends Source {
     }
 
     WebSource other = (WebSource) obj;
-    if (uri == null) {
-      if (other.uri != null) {
-        return false;
-      }
-    } else if (!uri.equals(other.uri)) {
-      return false;
-    }
-
-    return true;
+    return Objects.equals(uri, other.uri);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index 5141a4b..dfd5b06 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -828,7 +828,7 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
     // publish the service component installed event
     ServiceComponentInstalledEvent event = new ServiceComponentInstalledEvent(getClusterId(),
         stackId.getStackName(), stackId.getStackVersion(), getServiceName(),
-        getServiceComponentName(), getHostName(), isRecoveryEnabled());
+        getServiceComponentName(), getHostName(), isRecoveryEnabled(), serviceComponent.isMasterComponent());
 
     eventPublisher.publish(event);
 
@@ -1309,10 +1309,11 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       String componentName = getServiceComponentName();
       String hostName = getHostName();
       boolean recoveryEnabled = isRecoveryEnabled();
+      boolean masterComponent = serviceComponent.isMasterComponent();
 
       ServiceComponentUninstalledEvent event = new ServiceComponentUninstalledEvent(
           clusterId, stackName, stackVersion, serviceName, componentName,
-          hostName, recoveryEnabled);
+          hostName, recoveryEnabled, masterComponent);
 
       eventPublisher.publish(event);
       deleteMetaData.addDeletedHostComponent(componentName,

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentSessionManagerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentSessionManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentSessionManagerTest.java
new file mode 100644
index 0000000..89f8998
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentSessionManagerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.agent;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.ambari.server.HostNotRegisteredException;
+import org.apache.ambari.server.state.Host;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AgentSessionManagerTest {
+
+  private AgentSessionManager underTest;
+
+  @Before
+  public void setUp() {
+    underTest = new AgentSessionManager();
+  }
+
+  @Test
+  public void hostIsRegistered() throws HostNotRegisteredException {
+    String sessionId = "session ID";
+    String hostName = "example.com";
+    Host host = EasyMock.createNiceMock(Host.class);
+    expect(host.getHostName()).andReturn(hostName).anyTimes();
+    replay(host);
+
+    underTest.register(sessionId, host);
+
+    assertTrue(underTest.isRegistered(sessionId));
+    assertEquals(sessionId, underTest.getSessionId(hostName));
+    assertSame(host, underTest.getHost(sessionId));
+  }
+
+  @Test(expected = HostNotRegisteredException.class)
+  public void exceptionThrownForUnknownHost() throws HostNotRegisteredException {
+    underTest.getSessionId("not registered host");
+  }
+
+  @Test(expected = HostNotRegisteredException.class)
+  public void exceptionThrownForUnknownSessionId() throws HostNotRegisteredException {
+    underTest.getHost("unknown session ID");
+  }
+
+  @Test
+  public void registerRemovesOldSessionId() throws HostNotRegisteredException {
+    String oldSessionId = "old session ID";
+    String newSessionId = "new session ID";
+    String hostName = "example.com";
+    Host host = EasyMock.createNiceMock(Host.class);
+    expect(host.getHostName()).andReturn(hostName).anyTimes();
+    replay(host);
+
+    underTest.register(oldSessionId, host);
+    underTest.register(newSessionId, host);
+
+    assertFalse(underTest.isRegistered(oldSessionId));
+    assertEquals(newSessionId, underTest.getSessionId(hostName));
+    assertSame(host, underTest.getHost(newSessionId));
+  }
+
+  @Test(expected = HostNotRegisteredException.class)
+  public void unregisterRemovesSessionId() throws HostNotRegisteredException {
+    String sessionId = "session ID";
+    String hostName = "example.com";
+    Host host = EasyMock.createNiceMock(Host.class);
+    expect(host.getHostName()).andReturn(hostName).anyTimes();
+    replay(host);
+
+    underTest.register(sessionId, host);
+    underTest.unregisterByHost(hostName);
+
+    assertFalse(underTest.isRegistered(sessionId));
+    underTest.getSessionId(sessionId);
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
index 663934f..6ab932c 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
@@ -163,7 +163,7 @@ public class KerberosIdentityCleanerTest extends EasyMockSupport {
   }
 
   private void uninstallComponent(String service, String component, String host) throws KerberosMissingAdminCredentialsException {
-    kerberosIdentityCleaner.componentRemoved(new ServiceComponentUninstalledEvent(CLUSTER_ID, "any", "any", service, component, host, false));
+    kerberosIdentityCleaner.componentRemoved(new ServiceComponentUninstalledEvent(CLUSTER_ID, "any", "any", service, component, host, false, false));
   }
 
   private void uninstallService(String service, List<Component> components) throws KerberosMissingAdminCredentialsException {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
index 50854ce..7cd6229 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/events/listeners/upgrade/HostVersionOutOfSyncListenerTest.java
@@ -514,7 +514,7 @@ public class HostVersionOutOfSyncListenerTest {
 
         ServiceComponentUninstalledEvent event = new ServiceComponentUninstalledEvent(
             c1.getClusterId(), clusterStackId.getStackName(), clusterStackId.getStackVersion(),
-            "HDFS", "DATANODE", sch.getHostName(), false);
+            "HDFS", "DATANODE", sch.getHostName(), false, false);
 
         m_eventPublisher.publish(event);
       }
@@ -585,7 +585,7 @@ public class HostVersionOutOfSyncListenerTest {
           .getServiceComponent(componentName), hostName));
       ServiceComponentInstalledEvent event = new ServiceComponentInstalledEvent(cl.getClusterId(),
           stackIdObj.getStackName(), stackIdObj.getStackVersion(),
-          serviceName, componentName, hostName, false /* recovery not enabled */);
+          serviceName, componentName, hostName, false /* recovery not enabled */, false);
       m_eventPublisher.publish(event);
     }
   }


[2/2] ambari git commit: AMBARI-21803. Implement STOMP endpoint for alert definitions

Posted by ad...@apache.org.
AMBARI-21803. Implement STOMP endpoint for alert definitions


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f0def7ce
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f0def7ce
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f0def7ce

Branch: refs/heads/branch-3.0-perf
Commit: f0def7cec51bbfc9ad6ded071e1b481b49b6fee2
Parents: d632c01
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Tue Aug 22 16:45:59 2017 +0200
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Tue Oct 3 08:34:37 2017 +0200

----------------------------------------------------------------------
 .../ClusterAlertDefinitionsCache.py             |   6 +-
 .../src/main/python/ambari_agent/Constants.py   |   2 +-
 .../listeners/AlertDefinitionsEventListener.py  |   2 +-
 .../server/HostNotRegisteredException.java      |  18 +-
 .../server/agent/AgentSessionManager.java       |  60 ++--
 .../server/agent/AlertDefinitionCommand.java    |  10 +-
 .../agent/stomp/AgentClusterDataHolder.java     |  69 +++--
 .../server/agent/stomp/AgentConfigsHolder.java  |  24 +-
 .../agent/stomp/AgentCurrentDataController.java |  17 +-
 .../server/agent/stomp/AgentDataHolder.java     |  20 +-
 .../server/agent/stomp/AgentHostDataHolder.java |  77 +++--
 .../agent/stomp/AlertDefinitionsHolder.java     | 212 ++++++++++++++
 .../agent/stomp/HostLevelParamsHolder.java      |  17 +-
 .../server/agent/stomp/MetadataHolder.java      |  35 +--
 .../server/agent/stomp/TopologyHolder.java      |  70 ++---
 .../server/agent/stomp/dto/AlertCluster.java    |  95 +++++++
 .../server/agent/stomp/dto/MetadataCluster.java |  39 +--
 .../configuration/spring/ApiStompConfig.java    |  10 +-
 .../server/events/AgentConfigsUpdateEvent.java  |  25 +-
 .../events/AlertDefinitionUpdateHolder.java     | 116 --------
 .../events/AlertDefinitionsUpdateEvent.java     | 282 ++++---------------
 .../ambari/server/events/AmbariUpdateEvent.java |   4 +-
 .../events/HostLevelParamsUpdateEvent.java      |  28 +-
 .../server/events/MetadataUpdateEvent.java      |  24 +-
 .../events/ServiceComponentInstalledEvent.java  |  23 +-
 .../ServiceComponentUninstalledEvent.java       |  20 +-
 .../server/events/TopologyAgentUpdateEvent.java |   6 +-
 .../server/events/TopologyUpdateEvent.java      |  32 +--
 .../listeners/alerts/AlertReceivedListener.java |  20 +-
 .../listeners/requests/StateUpdateListener.java |  20 +-
 .../server/orm/dao/AlertDefinitionDAO.java      |  18 --
 .../server/state/alert/AggregateSource.java     |  30 +-
 .../server/state/alert/AlertDefinition.java     |   5 +
 .../server/state/alert/AlertDefinitionHash.java |  48 ++--
 .../ambari/server/state/alert/AlertUri.java     |  16 ++
 .../ambari/server/state/alert/AmsSource.java    |  43 +--
 .../ambari/server/state/alert/MetricSource.java |  52 +---
 .../server/state/alert/ParameterizedSource.java |  99 ++-----
 .../server/state/alert/PercentSource.java       |  88 ++----
 .../ambari/server/state/alert/PortSource.java   |  36 +--
 .../ambari/server/state/alert/Reporting.java    | 107 ++-----
 .../ambari/server/state/alert/ScriptSource.java |  29 +-
 .../ambari/server/state/alert/ServerSource.java |  20 +-
 .../ambari/server/state/alert/Source.java       |  40 +--
 .../ambari/server/state/alert/WebSource.java    |  21 +-
 .../svccomphost/ServiceComponentHostImpl.java   |   5 +-
 .../server/agent/AgentSessionManagerTest.java   |  99 +++++++
 .../utilities/KerberosIdentityCleanerTest.java  |   2 +-
 .../HostVersionOutOfSyncListenerTest.java       |   4 +-
 49 files changed, 1007 insertions(+), 1138 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-agent/src/main/python/ambari_agent/ClusterAlertDefinitionsCache.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/ClusterAlertDefinitionsCache.py b/ambari-agent/src/main/python/ambari_agent/ClusterAlertDefinitionsCache.py
index d3ab48e..914f453 100644
--- a/ambari-agent/src/main/python/ambari_agent/ClusterAlertDefinitionsCache.py
+++ b/ambari-agent/src/main/python/ambari_agent/ClusterAlertDefinitionsCache.py
@@ -69,7 +69,7 @@ class ClusterAlertDefinitionsCache(ClusterCache):
   def cache_update(self, cache_update, cache_hash):
     mutable_dict = self._get_mutable_copy()
 
-    for cluster_id in mutable_dict:
+    for cluster_id in cache_update:
       for alert_definition in cache_update[cluster_id]['alertDefinitions']:
         id_to_update = alert_definition['definitionId']
         index_of_alert = self.get_alert_definition_index_by_id(mutable_dict, cluster_id, id_to_update)
@@ -83,7 +83,7 @@ class ClusterAlertDefinitionsCache(ClusterCache):
   def cache_delete(self, cache_update, cache_hash):
     mutable_dict = self._get_mutable_copy()
 
-    for cluster_id in mutable_dict:
+    for cluster_id in cache_update:
       for alert_definition in cache_update[cluster_id]['alertDefinitions']:
         id_to_update = alert_definition['definitionId']
         index_of_alert = self.get_alert_definition_index_by_id(mutable_dict, cluster_id, id_to_update)
@@ -97,4 +97,4 @@ class ClusterAlertDefinitionsCache(ClusterCache):
 
 
   def get_cache_name(self):
-    return 'alert_definitions'
\ No newline at end of file
+    return 'alert_definitions'

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-agent/src/main/python/ambari_agent/Constants.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Constants.py b/ambari-agent/src/main/python/ambari_agent/Constants.py
index 4c0b01b..4e28863 100644
--- a/ambari-agent/src/main/python/ambari_agent/Constants.py
+++ b/ambari-agent/src/main/python/ambari_agent/Constants.py
@@ -44,4 +44,4 @@ HEARTBEAT_ENDPOINT = '/heartbeat'
 REGISTRATION_ENDPOINT = '/register'
 
 AGENT_TMP_DIR = "/var/lib/ambari-agent/tmp"
-CORRELATION_ID_STRING = 'correlationId'
\ No newline at end of file
+CORRELATION_ID_STRING = 'correlationId'

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-agent/src/main/python/ambari_agent/listeners/AlertDefinitionsEventListener.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/listeners/AlertDefinitionsEventListener.py b/ambari-agent/src/main/python/ambari_agent/listeners/AlertDefinitionsEventListener.py
index 494d0f3..8f52be4 100644
--- a/ambari-agent/src/main/python/ambari_agent/listeners/AlertDefinitionsEventListener.py
+++ b/ambari-agent/src/main/python/ambari_agent/listeners/AlertDefinitionsEventListener.py
@@ -59,4 +59,4 @@ class AlertDefinitionsEventListener(EventListener):
     self.alert_scheduler_handler.update_definitions(event_type)
 
   def get_handled_path(self):
-    return Constants.ALERTS_DEFINITIONS_TOPIC
\ No newline at end of file
+    return Constants.ALERTS_DEFINITIONS_TOPIC

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/HostNotRegisteredException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/HostNotRegisteredException.java b/ambari-server/src/main/java/org/apache/ambari/server/HostNotRegisteredException.java
index 9e7b3a7..eadd5f1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/HostNotRegisteredException.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/HostNotRegisteredException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -23,11 +23,15 @@ package org.apache.ambari.server;
  */
 public class HostNotRegisteredException extends AmbariException {
 
-  /**
-   * Constructor
-   * @param sessionId sessionId of websocket message
-   */
-  public HostNotRegisteredException(String sessionId) {
-    super(String.format("Host with [%s] sessionId not registered", sessionId));
+  public static HostNotRegisteredException forSessionId(String sessionId) {
+    return new HostNotRegisteredException(String.format("Host with sessionId '%s' not registered", sessionId));
+  }
+
+  public static HostNotRegisteredException forHostName(String hostName) {
+    return new HostNotRegisteredException(String.format("Host with hostName '%s' not registered", hostName));
+  }
+
+  private HostNotRegisteredException(String message) {
+    super(message);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentSessionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentSessionManager.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentSessionManager.java
index 1f64fc1..3040f55 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentSessionManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/AgentSessionManager.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -17,28 +17,31 @@
  */
 package org.apache.ambari.server.agent;
 
-import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.ambari.server.HostNotRegisteredException;
 import org.apache.ambari.server.state.Host;
 
+import com.google.common.base.Preconditions;
 import com.google.inject.Singleton;
 
 @Singleton
 public class AgentSessionManager {
-  private ConcurrentHashMap<String, Host> registeredHosts = new ConcurrentHashMap<>();
-  private ConcurrentHashMap<String, String> registeredSessionIds = new ConcurrentHashMap<>();
-
-  public void register(String sessionId, Host registeredHost) {
-    String existKey = registeredHosts.entrySet().stream()
-        .filter(e -> e.getValue().getHostName().equals(registeredHost.getHostName())).map(Map.Entry::getKey)
-        .findAny().orElse(null);
-    if (existKey != null) {
-      registeredHosts.remove(existKey);
+
+  private final ConcurrentMap<String, Host> registeredHosts = new ConcurrentHashMap<>(); // session ID -> host
+  private final ConcurrentMap<String, String> registeredSessionIds = new ConcurrentHashMap<>(); // hostname -> session ID
+
+  public void register(String sessionId, Host host) {
+    Preconditions.checkNotNull(sessionId);
+    Preconditions.checkNotNull(host);
+    Preconditions.checkNotNull(host.getHostName());
+
+    String oldSessionId = registeredSessionIds.put(host.getHostName(), sessionId);
+    if (oldSessionId != null) {
+      registeredHosts.remove(oldSessionId);
     }
-    registeredHosts.put(sessionId, registeredHost);
-    registeredSessionIds.put(registeredHost.getHostName(), sessionId);
+    registeredHosts.put(sessionId, host);
   }
 
   public boolean isRegistered(String sessionId) {
@@ -46,26 +49,33 @@ public class AgentSessionManager {
   }
 
   public Host getHost(String sessionId) throws HostNotRegisteredException {
-    if (registeredHosts.containsKey(sessionId)) {
-      return registeredHosts.get(sessionId);
+    Preconditions.checkNotNull(sessionId);
+
+    Host host = registeredHosts.get(sessionId);
+    if (host != null) {
+      return host;
     }
-    throw new HostNotRegisteredException(sessionId);
+
+    throw HostNotRegisteredException.forSessionId(sessionId);
   }
 
   public String getSessionId(String hostName) throws HostNotRegisteredException {
-    if (registeredSessionIds.containsKey(hostName)) {
-      return registeredSessionIds.get(hostName);
+    Preconditions.checkNotNull(hostName);
+
+    String sessionId = registeredSessionIds.get(hostName);
+    if (sessionId != null) {
+      return sessionId;
     }
-    throw new HostNotRegisteredException(hostName);
+
+    throw HostNotRegisteredException.forHostName(hostName);
   }
 
   public void unregisterByHost(String hostName) {
-    String existKey = registeredHosts.entrySet().stream()
-        .filter(e -> e.getValue().getHostName().equals(hostName)).map(Map.Entry::getKey)
-        .findAny().orElse(null);
-    if (existKey != null) {
-      registeredHosts.remove(existKey);
-      registeredSessionIds.remove(hostName);
+    Preconditions.checkNotNull(hostName);
+
+    String sessionId = registeredSessionIds.remove(hostName);
+    if (sessionId != null) {
+      registeredHosts.remove(sessionId);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
index a4324ee..59f20a3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/AlertDefinitionCommand.java
@@ -26,6 +26,7 @@ import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.alert.AlertDefinition;
 import org.apache.ambari.server.state.alert.AlertDefinitionHash;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.gson.annotations.SerializedName;
 
 /**
@@ -41,26 +42,23 @@ import com.google.gson.annotations.SerializedName;
  */
 public class AlertDefinitionCommand extends AgentCommand {
   @SerializedName("clusterName")
-  @com.fasterxml.jackson.annotation.JsonProperty("clusterName")
   private final String m_clusterName;
 
   @SerializedName("hostName")
-  @com.fasterxml.jackson.annotation.JsonProperty("hostName")
   private final String m_hostName;
 
   @SerializedName("publicHostName")
   private final String m_publicHostName;
 
   @SerializedName("hash")
-  @com.fasterxml.jackson.annotation.JsonProperty("hash")
   private final String m_hash;
 
   @SerializedName("alertDefinitions")
-  @com.fasterxml.jackson.annotation.JsonProperty("alertDefinitions")
+  @JsonProperty("alertDefinitions")
   private final List<AlertDefinition> m_definitions;
 
   @SerializedName("configurations")
-  @com.fasterxml.jackson.annotation.JsonProperty("configurations")
+  @JsonProperty("configurations")
   private Map<String, Map<String, String>> m_configurations;
 
   /**
@@ -117,6 +115,7 @@ public class AlertDefinitionCommand extends AgentCommand {
    *
    * @return the cluster name (not {@code null}).
    */
+  @JsonProperty("clusterName")
   public String getClusterName() {
     return m_clusterName;
   }
@@ -126,6 +125,7 @@ public class AlertDefinitionCommand extends AgentCommand {
    *
    * @return the host name (not {@code null}).
    */
+  @JsonProperty("hostName")
   public String getHostName() {
     return m_hostName;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentClusterDataHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentClusterDataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentClusterDataHolder.java
index 0f0a491..11f299c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentClusterDataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentClusterDataHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,44 +18,73 @@
 
 package org.apache.ambari.server.agent.stomp;
 
+import java.util.Objects;
+
+import javax.inject.Inject;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
-import org.apache.commons.lang.StringUtils;
+import org.apache.ambari.server.events.AmbariUpdateEvent;
+import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 
 /**
  * Is used to saving and updating last version of event in cluster scope
  * @param <T> event with hash to control version
  */
-public abstract class AgentClusterDataHolder<T extends Hashable> extends AgentDataHolder {
+public abstract class AgentClusterDataHolder<T extends AmbariUpdateEvent & Hashable> extends AgentDataHolder<T> {
+
+  @Inject
+  protected StateUpdateEventPublisher stateUpdateEventPublisher;
+
   private T data;
 
   public T getUpdateIfChanged(String agentHash) throws AmbariException {
-    if (StringUtils.isEmpty(agentHash) || (StringUtils.isNotEmpty(agentHash) && (data == null || !agentHash.equals(data.getHash())))) {
-      if (data == null) {
-        data = getCurrentData();
-        data.setHash(getHash(data));
-      }
-      return data;
-    }
-    return getEmptyData();
+    initializeDataIfNeeded(true);
+    return !Objects.equals(agentHash, data.getHash()) ? data : getEmptyData();
   }
 
+  /**
+   * Builds an update with the full set of current data.
+   * The eventType should be "CREATE", if applicable.
+   */
   protected abstract T getCurrentData() throws AmbariException;
 
-  protected abstract T getEmptyData();
+  /**
+   * Handle an incremental update to the data.
+   * @return true if the update introduced any change
+   */
+  protected abstract boolean handleUpdate(T update) throws AmbariException;
 
-  protected void regenerateHash() {
-    getData().setHash(null);
-    getData().setHash(getHash(getData()));
+  /**
+   * Template method to update the data.
+   * @return true if the update introduced any change
+   */
+  public boolean updateData(T update) throws AmbariException {
+    initializeDataIfNeeded(false);
+    boolean changed = handleUpdate(update);
+    if (changed) {
+      regenerateHash();
+      update.setHash(getData().getHash());
+      stateUpdateEventPublisher.publish(update);
+    }
+    return changed;
   }
 
-  public abstract void updateData(T update) throws AmbariException;
+  protected final void regenerateHash() {
+    regenerateHash(data);
+  }
 
-  public T getData() {
-    return data;
+  protected final void initializeDataIfNeeded(boolean regenerateHash) throws AmbariException {
+    if (data == null) {
+      data = getCurrentData();
+      if (regenerateHash) {
+        regenerateHash();
+      }
+    }
   }
 
-  public void setData(T data) {
-    this.data = data;
+  public final T getData() {
+    return data;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentConfigsHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentConfigsHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentConfigsHolder.java
index 0de686d..54d8c23 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentConfigsHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentConfigsHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -21,9 +21,9 @@ import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.events.AgentConfigsUpdateEvent;
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.Host;
 import org.apache.commons.collections.CollectionUtils;
 
 import com.google.inject.Inject;
@@ -37,36 +37,32 @@ public class AgentConfigsHolder extends AgentHostDataHolder<AgentConfigsUpdateEv
   private ConfigHelper configHelper;
 
   @Inject
-  private Provider<Clusters> m_clusters;
-
-  @Inject
-  private StateUpdateEventPublisher stateUpdateEventPublisher;
+  private Provider<Clusters> clusters;
 
   @Override
   public AgentConfigsUpdateEvent getCurrentData(String hostName) throws AmbariException {
     return configHelper.getHostActualConfigs(hostName);
   }
 
-  public void updateData(AgentConfigsUpdateEvent update) throws AmbariException {
-    //do nothing
+  protected boolean handleUpdate(AgentConfigsUpdateEvent update) throws AmbariException {
+    setData(update, update.getHostName());
+    return true;
   }
 
   public void updateData(Long clusterId, List<String> hostNames) throws AmbariException {
     if (CollectionUtils.isEmpty(hostNames)) {
       // TODO cluster configs will be created before hosts assigning
-      if (CollectionUtils.isEmpty(m_clusters.get().getCluster(clusterId).getHosts())) {
-        hostNames = m_clusters.get().getHosts().stream().map(h -> h.getHostName()).collect(Collectors.toList());
+      if (CollectionUtils.isEmpty(clusters.get().getCluster(clusterId).getHosts())) {
+        hostNames = clusters.get().getHosts().stream().map(Host::getHostName).collect(Collectors.toList());
       } else {
-        hostNames = m_clusters.get().getCluster(clusterId).getHosts().stream().map(h -> h.getHostName()).collect(Collectors.toList());
+        hostNames = clusters.get().getCluster(clusterId).getHosts().stream().map(Host::getHostName).collect(Collectors.toList());
       }
     }
 
     for (String hostName : hostNames) {
       AgentConfigsUpdateEvent agentConfigsUpdateEvent = configHelper.getHostActualConfigs(hostName);
       agentConfigsUpdateEvent.setHostName(hostName);
-      setData(agentConfigsUpdateEvent, hostName);
-      regenerateHash(hostName);
-      stateUpdateEventPublisher.publish(agentConfigsUpdateEvent);
+      updateData(agentConfigsUpdateEvent);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentCurrentDataController.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentCurrentDataController.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentCurrentDataController.java
index 7035f38..5ea5f06 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentCurrentDataController.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentCurrentDataController.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -21,12 +21,11 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.AgentSessionManager;
 import org.apache.ambari.server.agent.stomp.dto.Hash;
 import org.apache.ambari.server.events.AgentConfigsUpdateEvent;
+import org.apache.ambari.server.events.AlertDefinitionsUpdateEvent;
 import org.apache.ambari.server.events.HostLevelParamsUpdateEvent;
 import org.apache.ambari.server.events.MetadataUpdateEvent;
 import org.apache.ambari.server.events.TopologyUpdateEvent;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.springframework.messaging.handler.annotation.Header;
 import org.springframework.messaging.handler.annotation.MessageMapping;
 import org.springframework.messaging.simp.annotation.SendToUser;
@@ -39,12 +38,13 @@ import com.google.inject.Injector;
 @SendToUser("/")
 @MessageMapping("/agents")
 public class AgentCurrentDataController {
-  private static Log LOG = LogFactory.getLog(AgentCurrentDataController.class);
+
   private final AgentSessionManager agentSessionManager;
   private final TopologyHolder topologyHolder;
   private final MetadataHolder metadataHolder;
   private final HostLevelParamsHolder hostLevelParamsHolder;
   private final AgentConfigsHolder agentConfigsHolder;
+  private final AlertDefinitionsHolder alertDefinitionsHolder;
 
   public AgentCurrentDataController(Injector injector) {
     agentSessionManager = injector.getInstance(AgentSessionManager.class);
@@ -52,6 +52,7 @@ public class AgentCurrentDataController {
     metadataHolder = injector.getInstance(MetadataHolder.class);
     hostLevelParamsHolder = injector.getInstance(HostLevelParamsHolder.class);
     agentConfigsHolder = injector.getInstance(AgentConfigsHolder.class);
+    alertDefinitionsHolder = injector.getInstance(AlertDefinitionsHolder.class);
   }
 
   @SubscribeMapping("/topologies")
@@ -64,7 +65,12 @@ public class AgentCurrentDataController {
     return metadataHolder.getUpdateIfChanged(hash.getHash());
   }
 
-  //TODO method should returns empty response in case hash is relevant
+  @SubscribeMapping("/alert_definitions")
+  public AlertDefinitionsUpdateEvent getAlertDefinitions(@Header String simpSessionId, Hash hash) throws AmbariException {
+    String hostName = agentSessionManager.getHost(simpSessionId).getHostName();
+    return alertDefinitionsHolder.getUpdateIfChanged(hash.getHash(), hostName);
+  }
+
   @SubscribeMapping("/configs")
   public AgentConfigsUpdateEvent getCurrentConfigs(@Header String simpSessionId, Hash hash) throws AmbariException {
     return agentConfigsHolder.getUpdateIfChanged(hash.getHash(), agentSessionManager.getHost(simpSessionId).getHostName());
@@ -74,4 +80,5 @@ public class AgentCurrentDataController {
   public HostLevelParamsUpdateEvent getCurrentHostLevelParams(@Header String simpSessionId, Hash hash) throws AmbariException {
     return hostLevelParamsHolder.getUpdateIfChanged(hash.getHash(), agentSessionManager.getHost(simpSessionId).getHostName());
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentDataHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentDataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentDataHolder.java
index 635611b..a8b0a32 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentDataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentDataHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -31,11 +31,16 @@ import com.google.gson.Gson;
  * @param <T> event with hash to control version
  */
 public abstract class AgentDataHolder<T extends Hashable> {
-  public final String salt = "";
+  private final String salt = "";
 
   protected abstract T getEmptyData();
 
-  protected String getHash(T data) {
+  final void regenerateHash(T data) {
+    data.setHash(null);
+    data.setHash(getHash(data));
+  }
+
+  private String getHash(T data) {
     String json = new Gson().toJson(data);
     String generatedPassword = null;
     try {
@@ -43,14 +48,11 @@ public abstract class AgentDataHolder<T extends Hashable> {
       md.update(salt.getBytes("UTF-8"));
       byte[] bytes = md.digest(json.getBytes("UTF-8"));
       StringBuilder sb = new StringBuilder();
-      for(int i=0; i< bytes.length ;i++){
-        sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
+      for (byte b : bytes) {
+        sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
       }
       generatedPassword = sb.toString();
-    }
-    catch (NoSuchAlgorithmException e){
-      e.printStackTrace();
-    } catch (UnsupportedEncodingException e) {
+    } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
       e.printStackTrace();
     }
     return generatedPassword;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentHostDataHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentHostDataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentHostDataHolder.java
index 792f10e..746b755 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentHostDataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AgentHostDataHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,51 +18,82 @@
 
 package org.apache.ambari.server.agent.stomp;
 
-import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.inject.Inject;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
-import org.apache.commons.lang.StringUtils;
+import org.apache.ambari.server.events.AmbariHostUpdateEvent;
+import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 
 /**
  * Is used to saving and updating last version of event in host scope
  * @param <T> event with hash to control version
  */
-public abstract class AgentHostDataHolder<T extends Hashable> extends AgentDataHolder {
-  private Map<String, T> data = new HashMap<>();
+public abstract class AgentHostDataHolder<T extends AmbariHostUpdateEvent & Hashable> extends AgentDataHolder<T> {
+
+  @Inject
+  private StateUpdateEventPublisher stateUpdateEventPublisher;
+
+  private final Map<String, T> data = new ConcurrentHashMap<>();
+
+  protected abstract T getCurrentData(String hostName) throws AmbariException;
+  protected abstract boolean handleUpdate(T update) throws AmbariException;
 
   public T getUpdateIfChanged(String agentHash, String hostName) throws AmbariException {
-    if (StringUtils.isEmpty(agentHash) || (StringUtils.isNotEmpty(agentHash) && (!data.containsKey(hostName)
-        || !agentHash.equals(data.get(hostName).getHash())))) {
-      if (!data.containsKey(hostName)) {
-        data.put(hostName, getCurrentData(hostName));
-        data.get(hostName).setHash(getHash(data.get(hostName)));
+    T hostData = initializeDataIfNeeded(hostName, true);
+    return !Objects.equals(agentHash, hostData.getHash()) ? hostData : getEmptyData();
+  }
+
+  private T initializeDataIfNeeded(String hostName, boolean regenerateHash) throws AmbariException {
+    T hostData = data.get(hostName);
+    if (hostData == null) {
+      hostData = getCurrentData(hostName);
+      if (regenerateHash) {
+        regenerateHash(hostData);
       }
-      return data.get(hostName);
+      data.put(hostName, hostData);
     }
-    return getEmptyData();
+    return hostData;
   }
 
-  protected abstract T getCurrentData(String hostName) throws AmbariException;
-
-  protected abstract T getEmptyData();
+  /**
+   * Apply an incremental update to the data (host-specific), and publish the
+   * event to listeners.
+   */
+  public final void updateData(T update) throws AmbariException {
+    initializeDataIfNeeded(update.getHostName(), false);
+    if (handleUpdate(update)) {
+      T hostData = getData(update.getHostName());
+      regenerateHash(hostData);
+      update.setHash(hostData.getHash());
+      stateUpdateEventPublisher.publish(update);
+    }
+  }
 
-  protected void regenerateHash(String hostName) {
-    getData(hostName).setHash(null);
-    getData(hostName).setHash(getHash(getData(hostName)));
+  /**
+   * Reset data for the given host.  Used if changes are complex and it's easier to re-create data from scratch.
+   */
+  public final void resetData(String hostName) throws AmbariException {
+    T newData = getCurrentData(hostName);
+    data.replace(hostName, newData);
+    stateUpdateEventPublisher.publish(newData);
   }
 
-  public abstract void updateData(T update) throws AmbariException;
+  /**
+   * Remove data for the given host.
+   */
+  public final void onHostRemoved(String hostName) {
+    data.remove(hostName);
+  }
 
   public Map<String, T> getData() {
     return data;
   }
 
-  public void setData(Map<String, T> data) {
-    this.data = data;
-  }
-
   public T getData(String hostName) {
     return data.get(hostName);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AlertDefinitionsHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AlertDefinitionsHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AlertDefinitionsHolder.java
new file mode 100644
index 0000000..6c6bdd4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/AlertDefinitionsHolder.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.agent.stomp;
+
+import static org.apache.ambari.server.events.AlertDefinitionsUpdateEvent.EventType.CREATE;
+import static org.apache.ambari.server.events.AlertDefinitionsUpdateEvent.EventType.DELETE;
+import static org.apache.ambari.server.events.AlertDefinitionsUpdateEvent.EventType.UPDATE;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.agent.stomp.dto.AlertCluster;
+import org.apache.ambari.server.events.AlertDefinitionChangedEvent;
+import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
+import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
+import org.apache.ambari.server.events.AlertDefinitionsUpdateEvent;
+import org.apache.ambari.server.events.HostsRemovedEvent;
+import org.apache.ambari.server.events.ServiceComponentInstalledEvent;
+import org.apache.ambari.server.events.ServiceComponentUninstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.apache.ambari.server.state.alert.AlertDefinitionHash;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.Subscribe;
+
+@Singleton
+public class AlertDefinitionsHolder extends AgentHostDataHolder<AlertDefinitionsUpdateEvent> {
+
+  private static final Logger LOG = LoggerFactory.getLogger(AlertDefinitionsHolder.class);
+
+  @Inject
+  private Provider<AlertDefinitionHash> helper;
+
+  @Inject
+  private Provider<Clusters> clusters;
+
+  @Inject
+  public AlertDefinitionsHolder(AmbariEventPublisher eventPublisher) {
+    eventPublisher.register(this);
+  }
+
+  @Override
+  protected AlertDefinitionsUpdateEvent getCurrentData(String hostName) throws AmbariException {
+    Map<Long, AlertCluster> result = new TreeMap<>();
+    Map<Long, Map<Long, AlertDefinition>> alertDefinitions = helper.get().getAlertDefinitions(hostName);
+    long count = 0;
+    for (Map.Entry<Long, Map<Long, AlertDefinition>> e : alertDefinitions.entrySet()) {
+      Long clusterId = e.getKey();
+      Map<Long, AlertDefinition> definitionMap = e.getValue();
+      result.put(clusterId, new AlertCluster(definitionMap, hostName));
+      count += definitionMap.size();
+    }
+    LOG.info("Loaded {} alert definitions for {} clusters for host {}", count, result.size(), hostName);
+    return new AlertDefinitionsUpdateEvent(CREATE, result, hostName);
+  }
+
+  @Override
+  protected AlertDefinitionsUpdateEvent getEmptyData() {
+    return AlertDefinitionsUpdateEvent.emptyEvent();
+  }
+
+  @Override
+  protected boolean handleUpdate(AlertDefinitionsUpdateEvent update) throws AmbariException {
+    Map<Long, AlertCluster> updateClusters = update.getClusters();
+    if (updateClusters.isEmpty()) {
+      return false;
+    }
+
+    String hostName = update.getHostName();
+    boolean changed = false;
+    Map<Long, AlertCluster> existingClusters = getData(hostName).getClusters();
+
+    switch (update.getEventType()) {
+      case UPDATE:
+      case DELETE:
+        if (!existingClusters.keySet().containsAll(updateClusters.keySet())) {
+          throw new AmbariException("Unknown clusters in update");
+        }
+        for (Map.Entry<Long, AlertCluster> e : updateClusters.entrySet()) {
+          changed |= existingClusters.get(e.getKey()).handleUpdate(update.getEventType(), e.getValue());
+        }
+        LOG.debug("Handled {} of alerts for {} cluster(s) on host {}, changed = {}", update.getEventType(), updateClusters.size(), hostName, changed);
+        break;
+      case CREATE:
+        if (!updateClusters.isEmpty()) {
+          if (!Sets.intersection(existingClusters.keySet(), updateClusters.keySet()).isEmpty()) {
+            throw new AmbariException("Existing clusters in create");
+          }
+          existingClusters.putAll(updateClusters);
+          LOG.debug("Handled {} of alerts for {} cluster(s)", update.getEventType(), updateClusters.size());
+          changed = true;
+        }
+        break;
+      default:
+        LOG.warn("Unhandled event type {}", update.getEventType());
+        break;
+    }
+
+    return changed;
+  }
+
+  @Subscribe
+  public void onAlertDefinitionRegistered(AlertDefinitionRegistrationEvent event) {
+    handleSingleDefinitionChange(UPDATE, event.getDefinition());
+  }
+
+  @Subscribe
+  public void onAlertDefinitionChanged(AlertDefinitionChangedEvent event) {
+    handleSingleDefinitionChange(UPDATE, event.getDefinition());
+  }
+
+  @Subscribe
+  public void onAlertDefinitionDeleted(AlertDefinitionDeleteEvent event) {
+    handleSingleDefinitionChange(DELETE, event.getDefinition());
+  }
+
+  @Subscribe
+  public void onServiceComponentInstalled(ServiceComponentInstalledEvent event) {
+    String hostName = event.getHostName();
+    String serviceName = event.getServiceName();
+    String componentName = event.getComponentName();
+
+    Map<Long, AlertDefinition> definitions = helper.get().findByServiceComponent(event.getClusterId(), serviceName, componentName);
+
+    if (event.isMasterComponent()) {
+      try {
+        Cluster cluster = clusters.get().getClusterById(event.getClusterId());
+        if (cluster.getService(serviceName).getServiceComponents().get(componentName).getServiceComponentHosts().containsKey(hostName)) {
+          definitions.putAll(helper.get().findByServiceMaster(event.getClusterId(), serviceName));
+        }
+      } catch (AmbariException e) {
+        String msg = String.format("Failed to get alert definitions for master component %s/%s", serviceName, componentName);
+        LOG.warn(msg, e);
+      }
+    }
+
+    Map<Long, AlertCluster> map = Collections.singletonMap(event.getClusterId(), new AlertCluster(definitions, hostName));
+    safelyUpdateData(new AlertDefinitionsUpdateEvent(UPDATE, map, hostName));
+  }
+
+  @Subscribe
+  public void onServiceComponentUninstalled(ServiceComponentUninstalledEvent event) {
+    String hostName = event.getHostName();
+    Map<Long, AlertDefinition> definitions = helper.get().findByServiceComponent(event.getClusterId(), event.getServiceName(), event.getComponentName());
+    if (event.isMasterComponent()) {
+      definitions.putAll(helper.get().findByServiceMaster(event.getClusterId(), event.getServiceName()));
+    }
+    Map<Long, AlertCluster> map = Collections.singletonMap(event.getClusterId(), new AlertCluster(definitions, hostName));
+    safelyUpdateData(new AlertDefinitionsUpdateEvent(DELETE, map, hostName));
+  }
+
+  @Subscribe
+  public void onHostsRemoved(HostsRemovedEvent event) {
+    for (String hostName : event.getHostNames()) {
+      onHostRemoved(hostName);
+    }
+  }
+
+  private void safelyUpdateData(AlertDefinitionsUpdateEvent event) {
+    try {
+      updateData(event);
+    } catch (AmbariException e) {
+      LOG.warn(String.format("Failed to %s alert definitions for host %s", event.getEventType(), event.getHostName()), e);
+    }
+  }
+
+  private void safelyResetData(String hostName) {
+    try {
+      resetData(hostName);
+    } catch (AmbariException e) {
+      LOG.warn(String.format("Failed to reset alert definitions for host %s", hostName), e);
+    }
+  }
+
+  private void handleSingleDefinitionChange(AlertDefinitionsUpdateEvent.EventType eventType, AlertDefinition alertDefinition) {
+    LOG.info("{} alert definition '{}'", eventType, alertDefinition);
+    Set<String> hosts = helper.get().invalidateHosts(alertDefinition);
+    for (String hostName : hosts) {
+      Map<Long, AlertCluster> update = Collections.singletonMap(alertDefinition.getClusterId(), new AlertCluster(alertDefinition, hostName));
+      AlertDefinitionsUpdateEvent event = new AlertDefinitionsUpdateEvent(eventType, update, hostName);
+      safelyUpdateData(event);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
index 3d17ef2..4e6d37c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/HostLevelParamsHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -24,7 +24,6 @@ import org.apache.ambari.server.agent.RecoveryConfigHelper;
 import org.apache.ambari.server.agent.stomp.dto.HostLevelParamsCluster;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.events.HostLevelParamsUpdateEvent;
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Host;
@@ -44,14 +43,6 @@ public class HostLevelParamsHolder extends AgentHostDataHolder<HostLevelParamsUp
   @Inject
   private Clusters clusters;
 
-  private StateUpdateEventPublisher stateUpdateEventPublisher;
-
-  @Inject
-  public HostLevelParamsHolder(StateUpdateEventPublisher stateUpdateEventPublisher) {
-    this.stateUpdateEventPublisher = stateUpdateEventPublisher;
-    stateUpdateEventPublisher.register(this);
-  }
-
   @Override
   public HostLevelParamsUpdateEvent getCurrentData(String hostName) throws AmbariException {
     TreeMap<String, HostLevelParamsCluster> hostLevelParamsClusters = new TreeMap<>();
@@ -69,12 +60,10 @@ public class HostLevelParamsHolder extends AgentHostDataHolder<HostLevelParamsUp
     return hostLevelParamsUpdateEvent;
   }
 
-  public void updateData(HostLevelParamsUpdateEvent update) throws AmbariException {
+  protected boolean handleUpdate(HostLevelParamsUpdateEvent update) throws AmbariException {
     //TODO implement update host level params process
     setData(update, update.getHostName());
-    regenerateHash(update.getHostName());
-    update.setHash(getData(update.getHostName()).getHash());
-    stateUpdateEventPublisher.publish(update);
+    return true;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
index b7e6806..104f278 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -23,7 +23,6 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.stomp.dto.MetadataCluster;
 import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
 import org.apache.ambari.server.events.MetadataUpdateEvent;
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 import org.apache.commons.collections.MapUtils;
 
 import com.google.inject.Inject;
@@ -35,35 +34,31 @@ public class MetadataHolder extends AgentClusterDataHolder<MetadataUpdateEvent>
   @Inject
   private AmbariManagementControllerImpl ambariManagementController;
 
-  @Inject
-  private StateUpdateEventPublisher stateUpdateEventPublisher;
-
   @Override
   public MetadataUpdateEvent getCurrentData() throws AmbariException {
     return ambariManagementController.getClustersMetadata();
   }
 
-  public void updateData(MetadataUpdateEvent update) throws AmbariException {
-    if (getData() == null) {
-      setData(getCurrentData());
-    }
+  @Override
+  protected boolean handleUpdate(MetadataUpdateEvent update) throws AmbariException {
+    boolean changed = false;
     if (MapUtils.isNotEmpty(update.getMetadataClusters())) {
       for (Map.Entry<String, MetadataCluster> metadataClusterEntry : update.getMetadataClusters().entrySet()) {
-        if (getData().getMetadataClusters().containsKey(metadataClusterEntry.getKey())) {
-          getData().getMetadataClusters().get(metadataClusterEntry.getKey()).getClusterLevelParams().putAll(
-              metadataClusterEntry.getValue().getClusterLevelParams());
-          getData().getMetadataClusters().get(metadataClusterEntry.getKey()).getServiceLevelParams().putAll(
-              metadataClusterEntry.getValue().getServiceLevelParams());
-          getData().getMetadataClusters().get(metadataClusterEntry.getKey()).getStatusCommandsToRun().addAll(
-              metadataClusterEntry.getValue().getStatusCommandsToRun());
+        MetadataCluster updatedCluster = metadataClusterEntry.getValue();
+        String clusterId = metadataClusterEntry.getKey();
+        Map<String, MetadataCluster> clusters = getData().getMetadataClusters();
+        if (clusters.containsKey(clusterId)) {
+          MetadataCluster cluster = clusters.get(clusterId);
+          cluster.getClusterLevelParams().putAll(updatedCluster.getClusterLevelParams());
+          cluster.getServiceLevelParams().putAll(updatedCluster.getServiceLevelParams());
+          cluster.getStatusCommandsToRun().addAll(updatedCluster.getStatusCommandsToRun());
         } else {
-          getData().getMetadataClusters().put(metadataClusterEntry.getKey(), metadataClusterEntry.getValue());
+          clusters.put(clusterId, updatedCluster);
         }
+        changed = true;
       }
     }
-    regenerateHash();
-    update.setHash(getData().getHash());
-    stateUpdateEventPublisher.publish(update);
+    return changed;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
index 0da5d83..55c0150 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/TopologyHolder.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -26,15 +26,12 @@ import java.util.stream.Collectors;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
-import org.apache.ambari.server.agent.HeartBeatHandler;
-import org.apache.ambari.server.agent.RecoveryConfigHelper;
 import org.apache.ambari.server.agent.stomp.dto.TopologyCluster;
 import org.apache.ambari.server.agent.stomp.dto.TopologyComponent;
 import org.apache.ambari.server.agent.stomp.dto.TopologyHost;
 import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
 import org.apache.ambari.server.events.TopologyAgentUpdateEvent;
 import org.apache.ambari.server.events.TopologyUpdateEvent;
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Host;
@@ -42,7 +39,6 @@ import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.StackId;
-import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.commons.collections.CollectionUtils;
 
 import com.google.inject.Inject;
@@ -50,11 +46,6 @@ import com.google.inject.Singleton;
 
 @Singleton
 public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent> {
-  @Inject
-  private HeartBeatHandler heartBeatHandler;
-
-  @Inject
-  private RecoveryConfigHelper recoveryConfigHelper;
 
   @Inject
   private AmbariManagementControllerImpl ambariManagementController;
@@ -62,14 +53,6 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
   @Inject
   private Clusters clusters;
 
-  protected StateUpdateEventPublisher stateUpdateEventPublisher;
-
-  @Inject
-  public TopologyHolder(StateUpdateEventPublisher stateUpdateEventPublisher) {
-    this.stateUpdateEventPublisher = stateUpdateEventPublisher;
-    stateUpdateEventPublisher.register(this);
-  }
-
   @Override
   public TopologyUpdateEvent getUpdateIfChanged(String agentHash) throws AmbariException {
     TopologyUpdateEvent topologyUpdateEvent = super.getUpdateIfChanged(agentHash);
@@ -80,8 +63,6 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
   /**
    * Is used during agent registering to provide base info about clusters topology.
    * @return filled TopologyUpdateEvent with info about all components and hosts in all clusters
-   * @throws InvalidStateTransitionException
-   * @throws AmbariException
    */
   @Override
   public TopologyUpdateEvent getCurrentData() throws AmbariException {
@@ -104,8 +85,9 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
 
             Set<String> hostNames = cl.getHosts(sch.getServiceName(), sch.getServiceComponentName());
             Set<Long> hostOrderIds = clusterHosts.stream()
-                .filter(h -> hostNames.contains(h.getHostName()))
-                .map(h -> h.getHostId()).collect(Collectors.toSet());
+              .filter(h -> hostNames.contains(h.getHostName()))
+              .map(Host::getHostId)
+              .collect(Collectors.toSet());
             String serviceName = sch.getServiceName();
             String componentName = sch.getServiceComponentName();
             StackId stackId = cl.getDesiredStackVersion();
@@ -126,15 +108,30 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
       topologyClusters.put(Long.toString(cl.getClusterId()),
           new TopologyCluster(topologyComponents, topologyHosts));
     }
-    TopologyUpdateEvent topologyUpdateEvent = new TopologyUpdateEvent(topologyClusters,
-        TopologyUpdateEvent.EventType.CREATE);
-    return topologyUpdateEvent;
+    return new TopologyUpdateEvent(topologyClusters, TopologyUpdateEvent.EventType.CREATE);
   }
 
-  public void updateData(TopologyUpdateEvent update) throws AmbariException {
-    if (getData() == null) {
-      setData(getCurrentData());
+  @Override
+  public boolean updateData(TopologyUpdateEvent update) throws AmbariException {
+    boolean changed = super.updateData(update);
+    if (changed) {
+      // it is not allowed to change existent update event before arriving to listener and converting to json
+      // so it is better to create copy
+      TopologyUpdateEvent copiedUpdate = update.deepCopy();
+      TopologyAgentUpdateEvent topologyAgentUpdateEvent = new TopologyAgentUpdateEvent(copiedUpdate.getClusters(),
+        copiedUpdate.getHash(),
+        copiedUpdate.getEventType()
+      );
+      prepareAgentTopology(topologyAgentUpdateEvent);
+      stateUpdateEventPublisher.publish(topologyAgentUpdateEvent);
     }
+
+    return changed;
+  }
+
+  @Override
+  protected boolean handleUpdate(TopologyUpdateEvent update) throws AmbariException {
+    boolean changed = false;
     TopologyUpdateEvent.EventType eventType = update.getEventType();
     for (Map.Entry<String, TopologyCluster> updatedCluster : update.getClusters().entrySet()) {
       String clusterId = updatedCluster.getKey();
@@ -144,31 +141,22 @@ public class TopologyHolder extends AgentClusterDataHolder<TopologyUpdateEvent>
             CollectionUtils.isEmpty(getData().getClusters().get(clusterId).getTopologyComponents()) &&
             CollectionUtils.isEmpty(getData().getClusters().get(clusterId).getTopologyHosts())) {
           getData().getClusters().remove(clusterId);
+          changed = true;
         } else {
           getData().getClusters().get(clusterId).update(update.getClusters().get(clusterId).getTopologyComponents(),
               update.getClusters().get(clusterId).getTopologyHosts(), eventType);
+          changed = true; // TODO check if really changed
         }
       } else {
         if (eventType.equals(TopologyUpdateEvent.EventType.UPDATE)) {
           getData().getClusters().put(clusterId, cluster);
+          changed = true;
         } else {
           throw new ClusterNotFoundException(Long.parseLong(clusterId));
         }
       }
     }
-
-    regenerateHash();
-    update.setHash(getData().getHash());
-    stateUpdateEventPublisher.publish(update);
-
-    // it is not allowed to change existent update event before arriving to listener and converting to json
-    // so it is better to create copy
-    TopologyUpdateEvent copiedUpdate = update.deepCopy();
-    TopologyAgentUpdateEvent topologyAgentUpdateEvent = new TopologyAgentUpdateEvent(copiedUpdate.getClusters(),
-        copiedUpdate.getHash(),
-        copiedUpdate.getEventType());
-    prepareAgentTopology(topologyAgentUpdateEvent);
-    stateUpdateEventPublisher.publish(topologyAgentUpdateEvent);
+    return changed;
   }
 
   private void prepareAgentTopology(TopologyUpdateEvent topologyUpdateEvent) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/AlertCluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/AlertCluster.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/AlertCluster.java
new file mode 100644
index 0000000..53859a6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/AlertCluster.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.agent.stomp.dto;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.events.AlertDefinitionsUpdateEvent;
+import org.apache.ambari.server.state.alert.AlertDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class AlertCluster {
+
+  private static final Logger LOG = LoggerFactory.getLogger(AlertCluster.class);
+
+  private final Map<Long, AlertDefinition> alertDefinitions;
+  private final String hostName;
+
+  public AlertCluster(AlertDefinition alertDefinition, String hostName) {
+    this(Collections.singletonMap(alertDefinition.getDefinitionId(), alertDefinition), hostName);
+  }
+
+  public AlertCluster(Map<Long, AlertDefinition> alertDefinitions, String hostName) {
+    this.alertDefinitions = new HashMap<>(alertDefinitions);
+    this.hostName = hostName;
+  }
+
+  @JsonProperty("alertDefinitions")
+  public Collection<AlertDefinition> getAlertDefinitions() {
+    return alertDefinitions.values();
+  }
+
+  @JsonProperty("hostName")
+  public String getHostName() {
+    return hostName;
+  }
+
+  public boolean handleUpdate(AlertDefinitionsUpdateEvent.EventType eventType, AlertCluster update) {
+    if (update.alertDefinitions.isEmpty()) {
+      return false;
+    }
+
+    boolean changed = false;
+
+    switch (eventType) {
+      case CREATE:
+        // FIXME should clear map first?
+      case UPDATE:
+        changed = !alertDefinitions.keySet().containsAll(update.alertDefinitions.keySet());
+        if (changed) {
+          alertDefinitions.putAll(update.alertDefinitions);
+        } else {
+          for (Map.Entry<Long, AlertDefinition> e : update.alertDefinitions.entrySet()) {
+            Long definitionId = e.getKey();
+            AlertDefinition newDefinition = e.getValue();
+            AlertDefinition oldDefinition = alertDefinitions.put(definitionId, newDefinition);
+            changed = changed || !oldDefinition.deeplyEquals(newDefinition);
+          }
+        }
+        LOG.debug("Handled {} of {} alerts, changed = {}", eventType, update.alertDefinitions.size(), changed);
+        break;
+      case DELETE:
+        changed = alertDefinitions.keySet().removeAll(update.alertDefinitions.keySet());
+        LOG.debug("Handled {} of {} alerts", eventType, update.alertDefinitions.size());
+        break;
+      default:
+        LOG.warn("Unhandled event type {}", eventType);
+        break;
+    }
+
+    return changed;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
index 3ee5ad6..8210779 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,7 +18,9 @@
 package org.apache.ambari.server.agent.stomp.dto;
 
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
+import java.util.SortedMap;
 import java.util.TreeMap;
 
 import org.apache.ambari.server.state.SecurityType;
@@ -30,11 +32,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class MetadataCluster {
   @JsonProperty("status_commands_to_run")
   private Set<String> statusCommandsToRun = new HashSet<>();
-  private TreeMap<String, MetadataServiceInfo> serviceLevelParams = new TreeMap<>();
-  private TreeMap<String, String> clusterLevelParams = new TreeMap<>();
+  private SortedMap<String, MetadataServiceInfo> serviceLevelParams = new TreeMap<>();
+  private SortedMap<String, String> clusterLevelParams = new TreeMap<>();
 
-  public MetadataCluster(SecurityType securityType, TreeMap<String,MetadataServiceInfo> serviceLevelParams,
-                         TreeMap<String, String> clusterLevelParams) {
+  public MetadataCluster(SecurityType securityType, SortedMap<String,MetadataServiceInfo> serviceLevelParams,
+                         SortedMap<String, String> clusterLevelParams) {
     if (securityType != null) {
       this.statusCommandsToRun.add("STATUS");
       if (SecurityType.KERBEROS.equals(securityType)) {
@@ -49,23 +51,15 @@ public class MetadataCluster {
     return statusCommandsToRun;
   }
 
-  public void setStatusCommandsToRun(Set<String> statusCommandsToRun) {
-    this.statusCommandsToRun = statusCommandsToRun;
-  }
-
-  public TreeMap<String, MetadataServiceInfo> getServiceLevelParams() {
+  public SortedMap<String, MetadataServiceInfo> getServiceLevelParams() {
     return serviceLevelParams;
   }
 
-  public void setServiceLevelParams(TreeMap<String, MetadataServiceInfo> serviceLevelParams) {
-    this.serviceLevelParams = serviceLevelParams;
-  }
-
-  public TreeMap<String, String> getClusterLevelParams() {
+  public SortedMap<String, String> getClusterLevelParams() {
     return clusterLevelParams;
   }
 
-  public void setClusterLevelParams(TreeMap<String, String> clusterLevelParams) {
+  public void setClusterLevelParams(SortedMap<String, String> clusterLevelParams) {
     this.clusterLevelParams = clusterLevelParams;
   }
 
@@ -76,18 +70,13 @@ public class MetadataCluster {
 
     MetadataCluster that = (MetadataCluster) o;
 
-    if (statusCommandsToRun != null ? !statusCommandsToRun.equals(that.statusCommandsToRun) : that.statusCommandsToRun != null)
-      return false;
-    if (serviceLevelParams != null ? !serviceLevelParams.equals(that.serviceLevelParams) : that.serviceLevelParams != null)
-      return false;
-    return clusterLevelParams != null ? clusterLevelParams.equals(that.clusterLevelParams) : that.clusterLevelParams == null;
+    return Objects.equals(statusCommandsToRun, that.statusCommandsToRun) &&
+      Objects.equals(serviceLevelParams, that.serviceLevelParams) &&
+      Objects.equals(clusterLevelParams, that.clusterLevelParams);
   }
 
   @Override
   public int hashCode() {
-    int result = statusCommandsToRun != null ? statusCommandsToRun.hashCode() : 0;
-    result = 31 * result + (serviceLevelParams != null ? serviceLevelParams.hashCode() : 0);
-    result = 31 * result + (clusterLevelParams != null ? clusterLevelParams.hashCode() : 0);
-    return result;
+    return Objects.hash(statusCommandsToRun, serviceLevelParams, clusterLevelParams);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/configuration/spring/ApiStompConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/spring/ApiStompConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/spring/ApiStompConfig.java
index 170fa17..e968b11 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/spring/ApiStompConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/spring/ApiStompConfig.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -19,8 +19,6 @@ package org.apache.ambari.server.configuration.spring;
 
 import org.apache.ambari.server.api.stomp.TestController;
 import org.apache.ambari.server.events.listeners.requests.StateUpdateListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
@@ -36,7 +34,6 @@ import com.google.inject.Injector;
 @ComponentScan(basePackageClasses = {TestController.class})
 @Import(RootStompConfig.class)
 public class ApiStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
-  private static final Logger LOG = LoggerFactory.getLogger(ApiStompConfig.class);
 
   @Bean
   public StateUpdateListener requestStatusListener(Injector injector) {
@@ -46,8 +43,7 @@ public class ApiStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
   @Override
   public void registerStompEndpoints(StompEndpointRegistry registry) {
     registry.addEndpoint("/v1")
-        .setAllowedOrigins("*");
-    registry.addEndpoint("/v1")
-        .setAllowedOrigins("*").withSockJS();
+      .setAllowedOrigins("*")
+      .withSockJS();
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/AgentConfigsUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AgentConfigsUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AgentConfigsUpdateEvent.java
index 640be2d..f0f17e1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AgentConfigsUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AgentConfigsUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,7 +18,8 @@
 
 package org.apache.ambari.server.events;
 
-import java.util.TreeMap;
+import java.util.Objects;
+import java.util.SortedMap;
 
 import org.apache.ambari.server.agent.stomp.dto.ClusterConfigs;
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
@@ -47,21 +48,13 @@ public class AgentConfigsUpdateEvent extends AmbariHostUpdateEvent implements Ha
    * Configs grouped by cluster id as keys.
    */
   @JsonProperty("clusters")
-  private TreeMap<String, ClusterConfigs> clustersConfigs = new TreeMap<>();
+  private final SortedMap<String, ClusterConfigs> clustersConfigs;
 
-  public AgentConfigsUpdateEvent(TreeMap<String, ClusterConfigs> clustersConfigs) {
+  public AgentConfigsUpdateEvent(SortedMap<String, ClusterConfigs> clustersConfigs) {
     super(Type.AGENT_CONFIGS);
     this.clustersConfigs = clustersConfigs;
   }
 
-  public TreeMap<String, ClusterConfigs> getClustersConfigs() {
-    return clustersConfigs;
-  }
-
-  public void setClustersConfigs(TreeMap<String, ClusterConfigs> clustersConfigs) {
-    this.clustersConfigs = clustersConfigs;
-  }
-
   @Override
   public String getHash() {
     return hash;
@@ -91,14 +84,12 @@ public class AgentConfigsUpdateEvent extends AmbariHostUpdateEvent implements Ha
 
     AgentConfigsUpdateEvent that = (AgentConfigsUpdateEvent) o;
 
-    if (hostName != null ? !hostName.equals(that.hostName) : that.hostName != null) return false;
-    return clustersConfigs != null ? clustersConfigs.equals(that.clustersConfigs) : that.clustersConfigs == null;
+    return Objects.equals(hostName, that.hostName) &&
+      Objects.equals(clustersConfigs, that.clustersConfigs);
   }
 
   @Override
   public int hashCode() {
-    int result = hostName != null ? hostName.hashCode() : 0;
-    result = 31 * result + (clustersConfigs != null ? clustersConfigs.hashCode() : 0);
-    return result;
+    return Objects.hash(hostName, clustersConfigs);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionUpdateHolder.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionUpdateHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionUpdateHolder.java
deleted file mode 100644
index e820401..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionUpdateHolder.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ambari.server.events;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.ambari.server.events.publishers.StateUpdateEventPublisher;
-import org.apache.commons.lang.StringUtils;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class AlertDefinitionUpdateHolder {
-  private Map<Long, AlertDefinitionsUpdateEvent> cachedEvents = new ConcurrentHashMap<>();
-
-  @Inject
-  private StateUpdateEventPublisher stateUpdateEventPublisher;
-
-  public void updateIfNeeded(AlertDefinitionsUpdateEvent event) {
-    if (cachedEvents.containsKey(event.getDefinitionId())) {
-      AlertDefinitionsUpdateEvent cachedUpdate = cachedEvents.get(event.getDefinitionId());
-      AlertDefinitionsUpdateEvent updateEvent = new AlertDefinitionsUpdateEvent(event.getDefinitionId());
-      boolean updated = false;
-
-      if (event.getClusterId() != cachedUpdate.getClusterId()) {
-        cachedUpdate.setClusterId(event.getClusterId());
-        updateEvent.setClusterId(event.getClusterId());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getComponentName(), cachedUpdate.getComponentName())) {
-        cachedUpdate.setComponentName(event.getComponentName());
-        updateEvent.setComponentName(event.getComponentName());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getDescription(), cachedUpdate.getDescription())) {
-        cachedUpdate.setDescription(event.getDescription());
-        updateEvent.setDescription(event.getDescription());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getHelpURL(), cachedUpdate.getHelpURL())) {
-        cachedUpdate.setHelpURL(event.getHelpURL());
-        updateEvent.setHelpURL(event.getHelpURL());
-        updated = true;
-      }
-      if (event.getInterval() != cachedUpdate.getInterval()) {
-        cachedUpdate.setInterval(event.getInterval());
-        updateEvent.setInterval(event.getInterval());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getLabel(), cachedUpdate.getLabel())) {
-        cachedUpdate.setLabel(event.getLabel());
-        updateEvent.setLabel(event.getLabel());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getName(), cachedUpdate.getName())) {
-        cachedUpdate.setName(event.getName());
-        updateEvent.setName(event.getName());
-        updated = true;
-      }
-      if (event.getRepeatTolerance() != cachedUpdate.getRepeatTolerance()) {
-        cachedUpdate.setRepeatTolerance(event.getRepeatTolerance());
-        updateEvent.setRepeatTolerance(event.getRepeatTolerance());
-        updated = true;
-      }
-      if (!event.getScope().equals(cachedUpdate.getScope())) {
-        cachedUpdate.setScope(event.getScope());
-        updateEvent.setScope(event.getScope());
-        updated = true;
-      }
-      if (!StringUtils.equals(event.getServiceName(), cachedUpdate.getServiceName())) {
-        cachedUpdate.setServiceName(event.getServiceName());
-        updateEvent.setServiceName(event.getServiceName());
-        updated = true;
-      }
-      if (!event.getSource().equals(cachedUpdate.getSource())) {
-        cachedUpdate.setSource(event.getSource());
-        updateEvent.setSource(event.getSource());
-        updated = true;
-      }
-      if (!event.getEnabled().equals(cachedUpdate.getEnabled())) {
-        cachedUpdate.setEnabled(event.getEnabled());
-        updateEvent.setEnabled(event.getEnabled());
-        updated = true;
-      }
-      if (!event.getRepeatToleranceEnabled().equals(cachedUpdate.getRepeatToleranceEnabled())) {
-        cachedUpdate.setRepeatToleranceEnabled(event.getRepeatToleranceEnabled());
-        updateEvent.setRepeatToleranceEnabled(event.getRepeatToleranceEnabled());
-        updated = true;
-      }
-      if (updated) {
-        stateUpdateEventPublisher.publish(updateEvent);
-      }
-    } else {
-      cachedEvents.put(event.getDefinitionId(), event);
-      stateUpdateEventPublisher.publish(event);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionsUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionsUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionsUpdateEvent.java
index cbe6e37..cc0b5fb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionsUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AlertDefinitionsUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,222 +18,63 @@
 
 package org.apache.ambari.server.events;
 
-import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
-import org.apache.ambari.server.state.alert.AlertDefinition;
-import org.apache.ambari.server.state.alert.Scope;
-import org.apache.ambari.server.state.alert.Source;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.ambari.server.agent.stomp.dto.AlertCluster;
+import org.apache.ambari.server.agent.stomp.dto.Hashable;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 /**
- * Contains info about alert definitions update. This update will be sent to all subscribed recipients.
+ * Contains info about alert definitions update. This update is specific to a single host.
  */
-@JsonInclude(JsonInclude.Include.NON_EMPTY)
-public class AlertDefinitionsUpdateEvent extends AmbariUpdateEvent {
-
-  @JsonProperty("clusterId")
-  private Long clusterId;
-
-  @JsonProperty("componentName")
-  private String componentName;
-
-  @JsonProperty("description")
-  private String description;
-
-  @JsonProperty("enabled")
-  private Boolean enabled;
-
-  @JsonProperty("helpUrl")
-  private String helpURL;
-
-  @JsonProperty("id")
-  private Long definitionId;
-
-  @JsonProperty("ignoreHost")
-  private Boolean ignoreHost;
-
-  @JsonProperty("interval")
-  private Integer interval;
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class AlertDefinitionsUpdateEvent extends AmbariHostUpdateEvent implements Hashable {
 
-  @JsonProperty("label")
-  private String label;
+  private final Map<Long, AlertCluster> clusters;
+  private final EventType eventType;
+  private final String hostName;
+  private String hash;
 
-  @JsonProperty("name")
-  private String name;
-
-  @JsonProperty("repeatTolerance")
-  private Integer repeatTolerance;
-
-  @JsonProperty("repeatToleranceEnabled")
-  private Boolean repeatToleranceEnabled;
-
-  @JsonProperty("scope")
-  private Scope scope;
-
-  @JsonProperty("serviceName")
-  private String serviceName;
-
-  @JsonProperty("source")
-  private Source source;
-
-  public AlertDefinitionsUpdateEvent(Long clusterId, String componentName, String description, Boolean enabled,
-                               String helpURL, Long definitionId, Boolean ignoreHost, Integer interval, String label,
-                               String name, Integer repeatTolerance, Boolean repeatToleranceEnabled, Scope scope,
-                               String serviceName, Source source) {
-    super(Type.ALERT_DEFINITIONS);
-    this.clusterId = clusterId;
-    this.componentName = componentName;
-    this.description = description;
-    this.enabled = enabled;
-    this.helpURL = helpURL;
-    this.definitionId = definitionId;
-    this.ignoreHost = ignoreHost;
-    this.interval = interval;
-    this.label = label;
-    this.name = name;
-    this.repeatTolerance = repeatTolerance;
-    this.repeatToleranceEnabled = repeatToleranceEnabled;
-    this.scope = scope;
-    this.serviceName = serviceName;
-    this.source = source;
+  public static AlertDefinitionsUpdateEvent emptyEvent() {
+    return new AlertDefinitionsUpdateEvent(null, null, null);
   }
 
-  public AlertDefinitionsUpdateEvent(AlertDefinition alertDefinition, Integer repeatTolerance, Boolean repeatToleranceEnabled) {
-    this(alertDefinition.getClusterId(), alertDefinition.getComponentName(), alertDefinition.getDescription(),
-        alertDefinition.isEnabled(), alertDefinition.getHelpURL(), alertDefinition.getDefinitionId(),
-        alertDefinition.isHostIgnored(), alertDefinition.getInterval(), alertDefinition.getLabel(),
-        alertDefinition.getName(), repeatTolerance, repeatToleranceEnabled, alertDefinition.getScope(),
-        alertDefinition.getServiceName(), alertDefinition.getSource());
-  }
-
-  public AlertDefinitionsUpdateEvent(long definitionId) {
+  public AlertDefinitionsUpdateEvent(EventType eventType, Map<Long, AlertCluster> clusters, String hostName) {
     super(Type.ALERT_DEFINITIONS);
-    this.definitionId = definitionId;
-  }
-
-  public AlertDefinitionsUpdateEvent(AlertDefinitionEntity alertDefinitionEntity) {
-    super(Type.ALERT_DEFINITIONS);
-  }
-
-  public Long getClusterId() {
-    return clusterId;
-  }
-
-  public void setClusterId(Long clusterId) {
-    this.clusterId = clusterId;
-  }
-
-  public String getComponentName() {
-    return componentName;
-  }
-
-  public void setComponentName(String componentName) {
-    this.componentName = componentName;
-  }
-
-  public String getDescription() {
-    return description;
-  }
-
-  public void setDescription(String description) {
-    this.description = description;
-  }
-
-  public Boolean getEnabled() {
-    return enabled;
-  }
-
-  public void setEnabled(Boolean enabled) {
-    this.enabled = enabled;
-  }
-
-  public String getHelpURL() {
-    return helpURL;
-  }
-
-  public void setHelpURL(String helpURL) {
-    this.helpURL = helpURL;
-  }
-
-  public Long getDefinitionId() {
-    return definitionId;
-  }
-
-  public void setDefinitionId(Long definitionId) {
-    this.definitionId = definitionId;
-  }
-
-  public Boolean getIgnoreHost() {
-    return ignoreHost;
-  }
-
-  public void setIgnoreHost(Boolean ignoreHost) {
-    this.ignoreHost = ignoreHost;
-  }
-
-  public Integer getInterval() {
-    return interval;
-  }
-
-  public void setInterval(Integer interval) {
-    this.interval = interval;
+    this.eventType = eventType;
+    this.clusters = clusters != null ? Collections.unmodifiableMap(clusters) : null;
+    this.hostName = hostName;
   }
 
-  public String getLabel() {
-    return label;
-  }
-
-  public void setLabel(String label) {
-    this.label = label;
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public void setName(String name) {
-    this.name = name;
-  }
-
-  public Integer getRepeatTolerance() {
-    return repeatTolerance;
-  }
-
-  public void setRepeatTolerance(Integer repeatTolerance) {
-    this.repeatTolerance = repeatTolerance;
-  }
-
-  public Boolean getRepeatToleranceEnabled() {
-    return repeatToleranceEnabled;
-  }
-
-  public void setRepeatToleranceEnabled(Boolean repeatToleranceEnabled) {
-    this.repeatToleranceEnabled = repeatToleranceEnabled;
-  }
-
-  public Scope getScope() {
-    return scope;
-  }
-
-  public void setScope(Scope scope) {
-    this.scope = scope;
+  @Override
+  public String getHash() {
+    return hash;
   }
 
-  public String getServiceName() {
-    return serviceName;
+  @Override
+  @JsonProperty("hash")
+  public void setHash(String hash) {
+    this.hash = hash;
   }
 
-  public void setServiceName(String serviceName) {
-    this.serviceName = serviceName;
+  @Override
+  @JsonProperty("hostName")
+  public String getHostName() {
+    return hostName;
   }
 
-  public Source getSource() {
-    return source;
+  @JsonProperty("eventType")
+  public EventType getEventType() {
+    return eventType;
   }
 
-  public void setSource(Source source) {
-    this.source = source;
+  @JsonProperty("clusters")
+  public Map<Long, AlertCluster> getClusters() {
+    return clusters;
   }
 
   @Override
@@ -241,44 +82,25 @@ public class AlertDefinitionsUpdateEvent extends AmbariUpdateEvent {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
 
-    AlertDefinitionsUpdateEvent that = (AlertDefinitionsUpdateEvent) o;
+    AlertDefinitionsUpdateEvent other = (AlertDefinitionsUpdateEvent) o;
 
-    if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) return false;
-    if (componentName != null ? !componentName.equals(that.componentName) : that.componentName != null) return false;
-    if (description != null ? !description.equals(that.description) : that.description != null) return false;
-    if (enabled != null ? !enabled.equals(that.enabled) : that.enabled != null) return false;
-    if (helpURL != null ? !helpURL.equals(that.helpURL) : that.helpURL != null) return false;
-    if (definitionId != null ? !definitionId.equals(that.definitionId) : that.definitionId != null) return false;
-    if (ignoreHost != null ? !ignoreHost.equals(that.ignoreHost) : that.ignoreHost != null) return false;
-    if (interval != null ? !interval.equals(that.interval) : that.interval != null) return false;
-    if (label != null ? !label.equals(that.label) : that.label != null) return false;
-    if (name != null ? !name.equals(that.name) : that.name != null) return false;
-    if (repeatTolerance != null ? !repeatTolerance.equals(that.repeatTolerance) : that.repeatTolerance != null)
-      return false;
-    if (repeatToleranceEnabled != null ? !repeatToleranceEnabled.equals(that.repeatToleranceEnabled) : that.repeatToleranceEnabled != null)
-      return false;
-    if (scope != that.scope) return false;
-    if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) return false;
-    return source != null ? source.equals(that.source) : that.source == null;
+    return Objects.equals(eventType, other.eventType) &&
+      Objects.equals(clusters, other.clusters);
   }
 
   @Override
   public int hashCode() {
-    int result = clusterId != null ? clusterId.hashCode() : 0;
-    result = 31 * result + (componentName != null ? componentName.hashCode() : 0);
-    result = 31 * result + (description != null ? description.hashCode() : 0);
-    result = 31 * result + (enabled != null ? enabled.hashCode() : 0);
-    result = 31 * result + (helpURL != null ? helpURL.hashCode() : 0);
-    result = 31 * result + (definitionId != null ? definitionId.hashCode() : 0);
-    result = 31 * result + (ignoreHost != null ? ignoreHost.hashCode() : 0);
-    result = 31 * result + (interval != null ? interval.hashCode() : 0);
-    result = 31 * result + (label != null ? label.hashCode() : 0);
-    result = 31 * result + (name != null ? name.hashCode() : 0);
-    result = 31 * result + (repeatTolerance != null ? repeatTolerance.hashCode() : 0);
-    result = 31 * result + (repeatToleranceEnabled != null ? repeatToleranceEnabled.hashCode() : 0);
-    result = 31 * result + (scope != null ? scope.hashCode() : 0);
-    result = 31 * result + (serviceName != null ? serviceName.hashCode() : 0);
-    result = 31 * result + (source != null ? source.hashCode() : 0);
-    return result;
+    return Objects.hash(eventType, clusters);
+  }
+
+  public enum EventType {
+    /** Full current alert definitions */
+    CREATE,
+    /** Remove existing alert definition */
+    DELETE,
+    /** Update existing alert definition, or add new one */
+    UPDATE,
+    ;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f0def7ce/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariUpdateEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariUpdateEvent.java
index 90aa704..6991f15 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/AmbariUpdateEvent.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -61,7 +61,7 @@ public abstract class AmbariUpdateEvent {
     REQUEST("/events/requests", "events.requests"),
     SERVICE("/events/services", "events.services"),
     HOST("/events/hosts", "events.hosts"),
-    ALERT_DEFINITIONS("/events/alert_definitions", "events.alert_definitions"),
+    ALERT_DEFINITIONS("/alert_definitions", "events.alert_definitions"),
     COMMAND("/commands", "events.commands");
 
     /**