Browse Source

AMBARI-6620. Alerts: DAO Relationships and Cascading (Jonathan Hurley via ncole)

Nate Cole 11 năm trước cách đây
mục cha
commit
7602acae48
17 tập tin đã thay đổi với 788 bổ sung170 xóa
  1. 24 9
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
  2. 23 7
      ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
  3. 89 9
      ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java
  4. 57 4
      ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
  5. 18 3
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java
  6. 35 9
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
  7. 14 2
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java
  8. 2 31
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java
  9. 4 1
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java
  10. 22 4
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java
  11. 12 3
      ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
  12. 14 6
      ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
  13. 2 2
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
  14. 76 0
      ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java
  15. 116 32
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
  16. 249 21
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java
  17. 31 27
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java

+ 24 - 9
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java

@@ -42,6 +42,7 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.alert.Scope;
 import org.apache.ambari.server.state.alert.SourceType;
 
 import com.google.gson.Gson;
@@ -129,8 +130,9 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     
     if (!requestMap.containsKey(ALERT_DEF_INTERVAL))
       throw new IllegalArgumentException("Check interval must be specified");
-    Long interval = Long.valueOf((String) requestMap.get(ALERT_DEF_INTERVAL));
     
+    Integer interval = Integer.valueOf((String) requestMap.get(ALERT_DEF_INTERVAL));
+
     if (!requestMap.containsKey(ALERT_DEF_NAME))
       throw new IllegalArgumentException("Definition name must be specified");
     
@@ -159,22 +161,28 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     Cluster cluster = getManagementController().getClusters().getCluster(clusterName);
     
     AlertDefinitionEntity entity = new AlertDefinitionEntity();
-    
     entity.setClusterId(Long.valueOf(cluster.getClusterId()));
     entity.setComponentName((String) requestMap.get(ALERT_DEF_COMPONENT_NAME));
     entity.setDefinitionName((String) requestMap.get(ALERT_DEF_NAME));
 
-    boolean b = requestMap.containsKey(ALERT_DEF_ENABLED) ?
+    boolean enabled = requestMap.containsKey(ALERT_DEF_ENABLED) ?
         Boolean.parseBoolean((String)requestMap.get(ALERT_DEF_ENABLED)) : true;
-    entity.setEnabled(b);
     
+    entity.setEnabled(enabled);
     entity.setHash(UUID.randomUUID().toString());
     entity.setScheduleInterval(interval);
-    entity.setScope((String) requestMap.get(ALERT_DEF_SCOPE));
     entity.setServiceName((String) requestMap.get(ALERT_DEF_SERVICE_NAME));
     entity.setSourceType((String) requestMap.get(ALERT_DEF_SOURCE_TYPE));
     entity.setSource(jsonObj.toString());
     
+    Scope scope = null;
+    String desiredScope = (String) requestMap.get(ALERT_DEF_SCOPE);
+    if (null != desiredScope && desiredScope.length() > 0) {
+      scope = Scope.valueOf(desiredScope);
+    }
+
+    entity.setScope(scope);
+
     return entity;
   }
 
@@ -242,12 +250,19 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
         }
         
         if (propertyMap.containsKey(ALERT_DEF_INTERVAL)) {
-          entity.setScheduleInterval(Long.valueOf(
+          entity.setScheduleInterval(Integer.valueOf(
               (String) propertyMap.get(ALERT_DEF_INTERVAL)));
         }
-        
-        if (propertyMap.containsKey(ALERT_DEF_SCOPE))
-          entity.setScope((String) propertyMap.get(ALERT_DEF_SCOPE));
+                
+        if (propertyMap.containsKey(ALERT_DEF_SCOPE)){
+          Scope scope = null;
+          String desiredScope = (String) propertyMap.get(ALERT_DEF_SCOPE);
+              
+          if (null != desiredScope && desiredScope.length() > 0)
+            scope = Scope.valueOf((desiredScope));
+         
+          entity.setScope(scope);
+        }
         
 
         if (propertyMap.containsKey(ALERT_DEF_SOURCE_TYPE))

+ 23 - 7
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java

@@ -22,7 +22,6 @@ import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
-import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 
 import com.google.inject.Inject;
@@ -48,6 +47,18 @@ public class AlertDefinitionDAO {
   @Inject
   DaoUtils daoUtils;
 
+  /**
+   * Alert history DAO.
+   */
+  @Inject
+  AlertsDAO alertsDao;
+
+  /**
+   * Alert dispatch DAO.
+   */
+  @Inject
+  AlertDispatchDAO dispatchDao;
+
   /**
    * Gets an alert definition with the specified ID.
    * 
@@ -55,7 +66,6 @@ public class AlertDefinitionDAO {
    *          the ID of the definition to retrieve.
    * @return the alert definition or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertDefinitionEntity findById(long definitionId) {
     return entityManagerProvider.get().find(AlertDefinitionEntity.class,
         definitionId);
@@ -71,7 +81,6 @@ public class AlertDefinitionDAO {
    *          the name of the definition (not {@code null}).
    * @return the alert definition or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertDefinitionEntity findByName(long clusterId, String definitionName) {
     TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertDefinitionEntity.findByName", AlertDefinitionEntity.class);
@@ -88,7 +97,6 @@ public class AlertDefinitionDAO {
    * @return all alert definitions or an empty list if none exist (never
    *         {@code null}).
    */
-  @RequiresSession
   public List<AlertDefinitionEntity> findAll() {
     TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertDefinitionEntity.findAll", AlertDefinitionEntity.class);
@@ -102,7 +110,6 @@ public class AlertDefinitionDAO {
    * @return all alert definitions or empty list if none exist (never
    *         {@code null}).
    */
-  @RequiresSession
   public List<AlertDefinitionEntity> findAll(long clusterId) {
     TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertDefinitionEntity.findAllInCluster", AlertDefinitionEntity.class);
@@ -148,13 +155,22 @@ public class AlertDefinitionDAO {
   }
 
   /**
-   * Removes the specified alert definition from the database.
+   * Removes the specified alert definition and all related history and
+   * associations from the database.
    * 
    * @param alertDefinition
    *          the definition to remove.
    */
   @Transactional
   public void remove(AlertDefinitionEntity alertDefinition) {
-    entityManagerProvider.get().remove(merge(alertDefinition));
+    alertDefinition = merge(alertDefinition);
+    dispatchDao.removeNoticeByDefinitionId(alertDefinition.getDefinitionId());
+    alertsDao.removeByDefinitionId(alertDefinition.getDefinitionId());
+
+    EntityManager entityManager = entityManagerProvider.get();
+
+    alertDefinition = findById(alertDefinition.getDefinitionId());
+    if (null != alertDefinition)
+      entityManager.remove(alertDefinition);
   }
 }

+ 89 - 9
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDispatchDAO.java

@@ -22,8 +22,8 @@ import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
-import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 
 import com.google.inject.Inject;
@@ -56,7 +56,6 @@ public class AlertDispatchDAO {
    *          the ID of the group to retrieve.
    * @return the group or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertGroupEntity findGroupById(long groupId) {
     return entityManagerProvider.get().find(AlertGroupEntity.class, groupId);
   }
@@ -68,11 +67,21 @@ public class AlertDispatchDAO {
    *          the ID of the target to retrieve.
    * @return the target or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertTargetEntity findTargetById(long targetId) {
     return entityManagerProvider.get().find(AlertTargetEntity.class, targetId);
   }
 
+  /**
+   * Gets a notification with the specified ID.
+   * 
+   * @param noticeId
+   *          the ID of the notification to retrieve.
+   * @return the notification or {@code null} if none exists.
+   */
+  public AlertNoticeEntity findNoticeById(long noticeId) {
+    return entityManagerProvider.get().find(AlertNoticeEntity.class, noticeId);
+  }
+
   /**
    * Gets an alert group with the specified name across all clusters. Alert
    * group names are unique within a cluster.
@@ -81,7 +90,6 @@ public class AlertDispatchDAO {
    *          the name of the group (not {@code null}).
    * @return the alert group or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertGroupEntity findGroupByName(String groupName) {
     TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertGroupEntity.findByName", AlertGroupEntity.class);
@@ -101,7 +109,6 @@ public class AlertDispatchDAO {
    *          the name of the group (not {@code null}).
    * @return the alert group or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertGroupEntity findGroupByName(long clusterId, String groupName) {
     TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertGroupEntity.findByNameInCluster", AlertGroupEntity.class);
@@ -120,7 +127,6 @@ public class AlertDispatchDAO {
    *          the name of the target (not {@code null}).
    * @return the alert target or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertTargetEntity findTargetByName(String targetName) {
     TypedQuery<AlertTargetEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertTargetEntity.findByName", AlertTargetEntity.class);
@@ -135,7 +141,6 @@ public class AlertDispatchDAO {
    * 
    * @return all alert groups or empty list if none exist (never {@code null}).
    */
-  @RequiresSession
   public List<AlertGroupEntity> findAllGroups() {
     TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertGroupEntity.findAll", AlertGroupEntity.class);
@@ -149,7 +154,6 @@ public class AlertDispatchDAO {
    * @return all alert groups in the specified cluster or empty list if none
    *         exist (never {@code null}).
    */
-  @RequiresSession
   public List<AlertGroupEntity> findAllGroups(long clusterId) {
     TypedQuery<AlertGroupEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertGroupEntity.findAllInCluster", AlertGroupEntity.class);
@@ -164,7 +168,6 @@ public class AlertDispatchDAO {
    * 
    * @return all alert targets or empty list if none exist (never {@code null}).
    */
-  @RequiresSession
   public List<AlertTargetEntity> findAllTargets() {
     TypedQuery<AlertTargetEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertTargetEntity.findAll", AlertTargetEntity.class);
@@ -172,6 +175,19 @@ public class AlertDispatchDAO {
     return daoUtils.selectList(query);
   }
 
+  /**
+   * Gets all alert notifications stored in the database.
+   * 
+   * @return all alert notifications or empty list if none exist (never
+   *         {@code null}).
+   */
+  public List<AlertNoticeEntity> findAllNotices() {
+    TypedQuery<AlertNoticeEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertNoticeEntity.findAll", AlertNoticeEntity.class);
+
+    return daoUtils.selectList(query);
+  }
+
   /**
    * Persists a new alert group.
    * 
@@ -261,4 +277,68 @@ public class AlertDispatchDAO {
   public void remove(AlertTargetEntity alertTarget) {
     entityManagerProvider.get().remove(merge(alertTarget));
   }
+
+  /**
+   * Persists a new notification.
+   * 
+   * @param alertNotice
+   *          the notification to persist (not {@code null}).
+   */
+  @Transactional
+  public void create(AlertNoticeEntity alertNotice) {
+    entityManagerProvider.get().persist(alertNotice);
+  }
+
+  /**
+   * Refresh the state of the notification from the database.
+   * 
+   * @param alertNotice
+   *          the notification to refresh (not {@code null}).
+   */
+  @Transactional
+  public void refresh(AlertNoticeEntity alertNotice) {
+    entityManagerProvider.get().refresh(alertNotice);
+  }
+
+  /**
+   * Merge the specified notification with the existing target in the database.
+   * 
+   * @param alertNotice
+   *          the notification to merge (not {@code null}).
+   * @return the updated notification with merged content (never {@code null}).
+   */
+  @Transactional
+  public AlertNoticeEntity merge(AlertNoticeEntity alertNotice) {
+    return entityManagerProvider.get().merge(alertNotice);
+  }
+
+  /**
+   * Removes the specified notification from the database.
+   * 
+   * @param alertNotice
+   *          the notification to remove.
+   */
+  @Transactional
+  public void remove(AlertNoticeEntity alertNotice) {
+    entityManagerProvider.get().remove(merge(alertNotice));
+  }
+
+  /**
+   * Removes notifications for the specified alert definition ID. This will
+   * invoke {@link EntityManager#clear()} when completed since the JPQL
+   * statement will remove entries without going through the EM.
+   * 
+   * @param definitionId
+   *          the ID of the definition to remove.
+   */
+  @Transactional
+  public void removeNoticeByDefinitionId(long definitionId) {
+    EntityManager entityManager = entityManagerProvider.get();
+    TypedQuery<AlertNoticeEntity> currentQuery = entityManager.createNamedQuery(
+        "AlertNoticeEntity.removeByDefinitionId", AlertNoticeEntity.class);
+
+    currentQuery.setParameter("definitionId", definitionId);
+    currentQuery.executeUpdate();
+    entityManager.clear();
+  }
 }

+ 57 - 4
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java

@@ -60,7 +60,6 @@ public class AlertsDAO {
    *          the ID of the alert to retrieve.
    * @return the alert or {@code null} if none exists.
    */
-  @RequiresSession
   public AlertHistoryEntity findById(long alertId) {
     return entityManagerProvider.get().find(AlertHistoryEntity.class, alertId);
   }
@@ -70,7 +69,6 @@ public class AlertsDAO {
    * 
    * @return all alerts or an empty list if none exist (never {@code null}).
    */
-  @RequiresSession
   public List<AlertHistoryEntity> findAll() {
     TypedQuery<AlertHistoryEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertHistoryEntity.findAll", AlertHistoryEntity.class);
@@ -86,7 +84,6 @@ public class AlertsDAO {
    * @return all alerts in the specified cluster or an empty list if none exist
    *         (never {@code null}).
    */
-  @RequiresSession
   public List<AlertHistoryEntity> findAll(long clusterId) {
     TypedQuery<AlertHistoryEntity> query = entityManagerProvider.get().createNamedQuery(
         "AlertHistoryEntity.findAllInCluster", AlertHistoryEntity.class);
@@ -195,6 +192,18 @@ public class AlertsDAO {
     return daoUtils.selectList(query);
   }
 
+  /**
+   * Gets a current alert with the specified ID.
+   * 
+   * @param alertId
+   *          the ID of the alert to retrieve.
+   * @return the alert or {@code null} if none exists.
+   */
+  @RequiresSession
+  public AlertCurrentEntity findCurrentById(long alertId) {
+    return entityManagerProvider.get().find(AlertCurrentEntity.class, alertId);
+  }
+
   /**
    * Gets the current alerts for a given service.
    * 
@@ -231,6 +240,47 @@ public class AlertsDAO {
     return daoUtils.selectList(query);
   }
 
+  /**
+   * Removes alert history and current alerts for the specified alert defintiion
+   * ID. This will invoke {@link EntityManager#clear()} when completed since the
+   * JPQL statement will remove entries without going through the EM.
+   * 
+   * @param definitionId
+   *          the ID of the definition to remove.
+   */
+  @Transactional
+  public void removeByDefinitionId(long definitionId) {
+    EntityManager entityManager = entityManagerProvider.get();
+    TypedQuery<AlertCurrentEntity> currentQuery = entityManager.createNamedQuery(
+        "AlertCurrentEntity.removeByDefinitionId", AlertCurrentEntity.class);
+
+    currentQuery.setParameter("definitionId", definitionId);
+    currentQuery.executeUpdate();
+
+    TypedQuery<AlertHistoryEntity> historyQuery = entityManager.createNamedQuery(
+        "AlertHistoryEntity.removeByDefinitionId", AlertHistoryEntity.class);
+
+    historyQuery.setParameter("definitionId", definitionId);
+    historyQuery.executeUpdate();
+
+    entityManager.clear();
+  }
+
+  /**
+   * Remove a current alert whose history entry matches the specfied ID.
+   * 
+   * @param   historyId the ID of the history entry.
+   * @return  the number of alerts removed.
+   */
+  @Transactional
+  public int removeCurrentByHistoryId(long historyId) {
+    TypedQuery<AlertCurrentEntity> query = entityManagerProvider.get().createNamedQuery(
+        "AlertCurrentEntity.removeByHistoryId", AlertCurrentEntity.class);
+
+    query.setParameter("historyId", historyId);
+    return query.executeUpdate();
+  }
+
   /**
    * Persists a new alert.
    * 
@@ -273,7 +323,10 @@ public class AlertsDAO {
    */
   @Transactional
   public void remove(AlertHistoryEntity alert) {
-    entityManagerProvider.get().remove(merge(alert));
+    alert = merge(alert);
+
+    removeCurrentByHistoryId(alert.getAlertId());
+    entityManagerProvider.get().remove(alert);
   }
 
   /**

+ 18 - 3
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertCurrentEntity.java

@@ -21,12 +21,15 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.TableGenerator;
 
 import org.apache.ambari.server.state.MaintenanceState;
 
@@ -40,13 +43,17 @@ import org.apache.ambari.server.state.MaintenanceState;
  */
 @Entity
 @Table(name = "alert_current")
+@TableGenerator(name = "alert_current_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "value", pkColumnValue = "alert_current_id_seq", initialValue = 0, allocationSize = 1)
 @NamedQueries({
     @NamedQuery(name = "AlertCurrentEntity.findAll", query = "SELECT alert FROM AlertCurrentEntity alert"),
     @NamedQuery(name = "AlertCurrentEntity.findByService", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.serviceName = :serviceName"),
-    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName") })
+    @NamedQuery(name = "AlertCurrentEntity.findByHost", query = "SELECT alert FROM AlertCurrentEntity alert JOIN alert.alertHistory history WHERE history.clusterId = :clusterId AND history.hostName = :hostName"),
+    @NamedQuery(name = "AlertCurrentEntity.removeByHistoryId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertHistory.alertId = :historyId"),
+    @NamedQuery(name = "AlertCurrentEntity.removeByDefinitionId", query = "DELETE FROM AlertCurrentEntity alert WHERE alert.alertDefinition.definitionId = :definitionId") })
 public class AlertCurrentEntity {
 
   @Id
+  @GeneratedValue(strategy = GenerationType.TABLE, generator = "alert_current_id_generator")
   @Column(name = "alert_id", nullable = false, updatable = false)
   private Long alertId;
 
@@ -61,12 +68,19 @@ public class AlertCurrentEntity {
   private Long originalTimestamp;
 
   /**
-   * Bi-directional one-to-one association to {@link AlertHistoryEntity}
+   * Unidirectional one-to-one association to {@link AlertHistoryEntity}
    */
   @OneToOne
-  @JoinColumn(name = "alert_id", nullable = false, insertable = false, updatable = false)
+  @JoinColumn(name = "history_id", unique = true, nullable = false)
   private AlertHistoryEntity alertHistory;
 
+  /**
+   * Unidirectional one-to-one association to {@link AlertDefinitionEntity}
+   */
+  @OneToOne
+  @JoinColumn(name = "definition_id", unique = false, nullable = false)
+  private AlertDefinitionEntity alertDefinition;
+
   /**
    * Constructor.
    */
@@ -174,6 +188,7 @@ public class AlertCurrentEntity {
    */
   public void setAlertHistory(AlertHistoryEntity alertHistory) {
     this.alertHistory = alertHistory;
+    alertDefinition = alertHistory.getAlertDefinition();
   }
 
   /**

+ 35 - 9
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java

@@ -19,18 +19,25 @@ package org.apache.ambari.server.orm.entities;
 
 import java.util.Set;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EntityManager;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.ManyToMany;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.PreRemove;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 import javax.persistence.UniqueConstraint;
 
+import org.apache.ambari.server.state.alert.Scope;
+
 /**
  * The {@link AlertDefinitionEntity} class is used to model an alert that needs
  * to run in the system. Each received alert from an agent will essentially be
@@ -64,7 +71,8 @@ public class AlertDefinitionEntity {
   private String definitionName;
   
   @Column(name = "scope", length = 255)
-  private String scope;
+  @Enumerated(value = EnumType.STRING)
+  private Scope scope;
 
   @Column(nullable = false)
   private Integer enabled = Integer.valueOf(1);
@@ -73,7 +81,7 @@ public class AlertDefinitionEntity {
   private String hash;
 
   @Column(name = "schedule_interval", nullable = false)
-  private Long scheduleInterval;
+  private Integer scheduleInterval;
 
   @Column(name = "service_name", nullable = false, length = 255)
   private String serviceName;
@@ -84,7 +92,8 @@ public class AlertDefinitionEntity {
   /**
    * Bi-directional many-to-many association to {@link AlertGroupEntity}
    */
-  @ManyToMany(mappedBy = "alertDefinitions")
+  @ManyToMany(mappedBy = "alertDefinitions", cascade = { CascadeType.PERSIST,
+      CascadeType.MERGE, CascadeType.REFRESH })
   private Set<AlertGroupEntity> alertGroups;
 
   /**
@@ -180,22 +189,22 @@ public class AlertDefinitionEntity {
 
   /**
    * Gets the scope of the alert definition. The scope is defined as either
-   * being for a SERVICE or a HOST.
+   * being for a {@link Scope#SERVICE} or {@link Scope#HOST}.
    * 
    * @return the scope, or {@code null} if not defined.
    */
-  public String getScope() {
+  public Scope getScope() {
     return scope;
   }
 
   /**
    * Sets the scope of the alert definition. The scope is defined as either
-   * being for a SERVICE or a HOST.
+   * being for a {@link Scope#SERVICE} or {@link Scope#HOST}.
    * 
    * @param scope
    *          the scope to set, or {@code null} for none.
    */
-  public void setScope(String scope) {
+  public void setScope(Scope scope) {
     this.scope = scope;
   }
 
@@ -269,7 +278,7 @@ public class AlertDefinitionEntity {
    * 
    * @return the interval, in seconds.
    */
-  public Long getScheduleInterval() {
+  public Integer getScheduleInterval() {
     return scheduleInterval;
   }
 
@@ -279,7 +288,7 @@ public class AlertDefinitionEntity {
    * @param scheduleInterval
    *          the interval, in seconds.
    */
-  public void setScheduleInterval(Long scheduleInterval) {
+  public void setScheduleInterval(Integer scheduleInterval) {
     this.scheduleInterval = scheduleInterval;
   }
 
@@ -339,6 +348,23 @@ public class AlertDefinitionEntity {
     this.alertGroups = alertGroups;
   }
 
+  /**
+   * Called before {@link EntityManager#remove(Object)} for this entity, removes
+   * the non-owning relationship between definitions and groups.
+   */
+  @PreRemove
+  public void preRemove() {
+    Set<AlertGroupEntity> groups = getAlertGroups();
+    if (null == groups || groups.size() == 0)
+      return;
+
+    for (AlertGroupEntity group : groups) {
+      Set<AlertDefinitionEntity> definitions = group.getAlertDefinitions();
+      if (null != definitions)
+        definitions.remove(this);
+    }
+  }
+
   /**
    *
    */

+ 14 - 2
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertGroupEntity.java

@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.orm.entities;
 
+import java.util.HashSet;
 import java.util.Set;
 
 import javax.persistence.Column;
@@ -71,9 +72,10 @@ public class AlertGroupEntity {
   private Set<AlertDefinitionEntity> alertDefinitions;
 
   /**
-   * Bi-directional many-to-many association to {@link AlertTargetEntity}
+   * Unidirectional many-to-many association to {@link AlertTargetEntity}
    */
-  @ManyToMany(mappedBy = "alertGroups")
+  @ManyToMany
+  @JoinTable(name = "alert_group_target", joinColumns = { @JoinColumn(name = "group_id", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "target_id", nullable = false) })
   private Set<AlertTargetEntity> alertTargets;
 
   /**
@@ -201,6 +203,16 @@ public class AlertGroupEntity {
    */
   public void setAlertTargets(Set<AlertTargetEntity> alertTargets) {
     this.alertTargets = alertTargets;
+
+    if (null != alertTargets) {
+      for (AlertTargetEntity target : alertTargets) {
+        Set<AlertGroupEntity> groups = target.getAlertGroups();
+        if (null == groups)
+          groups = new HashSet<AlertGroupEntity>();
+
+        groups.add(this);
+      }
+    }
   }
 
   /**

+ 2 - 31
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity.java

@@ -28,7 +28,6 @@ import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
-import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
@@ -50,7 +49,8 @@ import org.apache.ambari.server.state.AlertState;
     @NamedQuery(name = "AlertHistoryEntity.findAllInClusterWithState", query = "SELECT alertHistory FROM AlertHistoryEntity alertHistory WHERE alertHistory.clusterId = :clusterId AND alertHistory.alertState IN :alertStates"),
     @NamedQuery(name = "AlertHistoryEntity.findAllInClusterBetweenDates", query = "SELECT alertHistory FROM AlertHistoryEntity alertHistory WHERE alertHistory.clusterId = :clusterId AND alertHistory.alertTimestamp BETWEEN :startDate AND :endDate"),
     @NamedQuery(name = "AlertHistoryEntity.findAllInClusterBeforeDate", query = "SELECT alertHistory FROM AlertHistoryEntity alertHistory WHERE alertHistory.clusterId = :clusterId AND alertHistory.alertTimestamp <= :beforeDate"),
-    @NamedQuery(name = "AlertHistoryEntity.findAllInClusterAfterDate", query = "SELECT alertHistory FROM AlertHistoryEntity alertHistory WHERE alertHistory.clusterId = :clusterId AND alertHistory.alertTimestamp >= :afterDate") })
+    @NamedQuery(name = "AlertHistoryEntity.findAllInClusterAfterDate", query = "SELECT alertHistory FROM AlertHistoryEntity alertHistory WHERE alertHistory.clusterId = :clusterId AND alertHistory.alertTimestamp >= :afterDate"),
+    @NamedQuery(name = "AlertHistoryEntity.removeByDefinitionId", query = "DELETE FROM AlertHistoryEntity alertHistory WHERE alertHistory.alertDefinition.definitionId = :definitionId") })
 public class AlertHistoryEntity {
 
   @Id
@@ -86,12 +86,6 @@ public class AlertHistoryEntity {
   @Column(name = "service_name", nullable = false, length = 255)
   private String serviceName;
 
-  /**
-   * Bi-directional one-to-one association to {@link AlertCurrentEntity}.
-   */
-  @OneToOne(mappedBy = "alertHistory", orphanRemoval = true)
-  private AlertCurrentEntity alertCurrent;
-
   /**
    * Unidirectional many-to-one association to {@link AlertDefinitionEntity}
    */
@@ -309,29 +303,6 @@ public class AlertHistoryEntity {
     this.serviceName = serviceName;
   }
 
-  /**
-   * Gets the current, active alert that is associated with this historical
-   * instance, if any. Once an alert state changes, the association between
-   * current and historical will be removed in favor of the newly received alert
-   * instance.
-   * 
-   * @return the associated current alert or {@code null} if this historical
-   *         item is not the most recent.
-   */
-  public AlertCurrentEntity getAlertCurrent() {
-    return alertCurrent;
-  }
-
-  /**
-   * Sets the associated current active alert with this historical instance.
-   * 
-   * @param alertCurrent
-   *          the current alert or {@code null} for none.
-   */
-  public void setAlertCurrent(AlertCurrentEntity alertCurrent) {
-    this.alertCurrent = alertCurrent;
-  }
-
   /**
    * Gets the associated alert definition for this alert instance. The alert
    * definition can be used to retrieve global information about an alert such

+ 4 - 1
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertNoticeEntity.java

@@ -26,6 +26,7 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
@@ -42,7 +43,9 @@ import org.apache.ambari.server.state.NotificationState;
 @Entity
 @Table(name = "alert_notice")
 @TableGenerator(name = "alert_notice_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "value", pkColumnValue = "alert_notice_id_seq", initialValue = 0, allocationSize = 1)
-@NamedQuery(name = "AlertNoticeEntity.findAll", query = "SELECT alertNotice FROM AlertNoticeEntity alertNotice")
+@NamedQueries({
+    @NamedQuery(name = "AlertNoticeEntity.findAll", query = "SELECT notice FROM AlertNoticeEntity notice"),
+    @NamedQuery(name = "AlertNoticeEntity.removeByDefinitionId", query = "DELETE FROM AlertNoticeEntity notice WHERE notice.alertHistory.alertDefinition.definitionId = :definitionId") })
 public class AlertNoticeEntity {
 
   @Id

+ 22 - 4
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertTargetEntity.java

@@ -19,16 +19,17 @@ package org.apache.ambari.server.orm.entities;
 
 import java.util.Set;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EntityManager;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
+import javax.persistence.PreRemove;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 
@@ -64,8 +65,8 @@ public class AlertTargetEntity {
   /**
    * Bi-directional many-to-many association to {@link AlertGroupEntity}
    */
-  @ManyToMany
-  @JoinTable(name = "alert_group_target", joinColumns = { @JoinColumn(name = "target_id", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "group_id", nullable = false) })
+  @ManyToMany(mappedBy = "alertTargets", cascade = { CascadeType.PERSIST,
+      CascadeType.MERGE })
   private Set<AlertGroupEntity> alertGroups;
 
   /**
@@ -180,6 +181,23 @@ public class AlertTargetEntity {
     this.alertGroups = alertGroups;
   }
 
+  /**
+   * Called before {@link EntityManager#remove(Object)} for this entity, removes
+   * the non-owning relationship between targets and groups.
+   */
+  @PreRemove
+  public void preRemove() {
+    Set<AlertGroupEntity> groups = getAlertGroups();
+    if (null == groups || groups.size() == 0)
+      return;
+
+    for (AlertGroupEntity group : groups) {
+      Set<AlertTargetEntity> targets = group.getAlertTargets();
+      if (null != targets)
+        targets.remove(this);
+    }
+  }
+
   /**
    *
    */

+ 12 - 3
ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql

@@ -169,7 +169,7 @@ CREATE TABLE alert_definition (
   component_name VARCHAR(255),
   scope VARCHAR(255),
   enabled SMALLINT DEFAULT 1 NOT NULL,
-  schedule_interval BIGINT NOT NULL,
+  schedule_interval INTEGER NOT NULL,
   source_type VARCHAR(255) NOT NULL,
   alert_source TEXT NOT NULL,
   hash VARCHAR(64) NOT NULL,
@@ -197,11 +197,14 @@ CREATE TABLE alert_history (
 
 CREATE TABLE alert_current (
   alert_id BIGINT NOT NULL,
+  definition_id BIGINT NOT NULL,
+  history_id BIGINT NOT NULL UNIQUE,
   maintenance_state VARCHAR(255),
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   PRIMARY KEY (alert_id),
-  FOREIGN KEY (alert_id) REFERENCES alert_history(alert_id)
+  FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id),
+  FOREIGN KEY (history_id) REFERENCES alert_history(alert_id)
 );
 
 CREATE TABLE alert_group (
@@ -225,6 +228,7 @@ CREATE TABLE alert_target (
 CREATE TABLE alert_group_target (
   group_id BIGINT NOT NULL,
   target_id BIGINT NOT NULL,
+  PRIMARY KEY (group_id, target_id),
   FOREIGN KEY (group_id) REFERENCES alert_group(group_id),
   FOREIGN KEY (target_id) REFERENCES alert_target(target_id)
 );
@@ -232,6 +236,7 @@ CREATE TABLE alert_group_target (
 CREATE TABLE alert_grouping (
   definition_id BIGINT NOT NULL,
   group_id BIGINT NOT NULL,
+  PRIMARY KEY (group_id, definition_id),
   FOREIGN KEY (definition_id) REFERENCES alert_definition(definition_id),
   FOREIGN KEY (group_id) REFERENCES alert_group(group_id)
 );
@@ -246,11 +251,13 @@ CREATE TABLE alert_notice (
   FOREIGN KEY (history_id) REFERENCES alert_history(alert_id)
 );
 
+CREATE INDEX idx_alert_history_def_id on alert_history(alert_definition_id);
 CREATE INDEX idx_alert_history_service on alert_history(service_name);
 CREATE INDEX idx_alert_history_host on alert_history(host_name);
 CREATE INDEX idx_alert_history_time on alert_history(alert_timestamp);
 CREATE INDEX idx_alert_history_state on alert_history(alert_state);
 CREATE INDEX idx_alert_group_name on alert_group(group_name);
+CREATE INDEX idx_alert_notice_state on alert_notice(notify_state);
 
 ---------inserting some data-----------
 BEGIN;
@@ -297,7 +304,9 @@ BEGIN;
   union all
   select 'alert_history_id_seq', 0
   union all
-  select 'alert_notice_id_seq', 0;
+  select 'alert_notice_id_seq', 0,
+  union all
+  select 'alert_current_id_seq', 0;
 
   INSERT INTO adminresourcetype (resource_type_id, resource_type_name)
   SELECT 1, 'AMBARI'

+ 14 - 6
ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql

@@ -232,7 +232,7 @@ CREATE TABLE ambari.alert_definition (
   component_name VARCHAR(255),
   scope VARCHAR(255),
   enabled SMALLINT DEFAULT 1 NOT NULL,
-  schedule_interval BIGINT NOT NULL,
+  schedule_interval INTEGER NOT NULL,
   source_type VARCHAR(255) NOT NULL,
   alert_source TEXT NOT NULL,
   hash VARCHAR(64) NOT NULL,
@@ -260,11 +260,14 @@ CREATE TABLE ambari.alert_history (
 
 CREATE TABLE ambari.alert_current (
   alert_id BIGINT NOT NULL,
+  definition_id BIGINT NOT NULL,
+  history_id BIGINT NOT NULL UNIQUE,
   maintenance_state VARCHAR(255),
   original_timestamp BIGINT NOT NULL,
   latest_timestamp BIGINT NOT NULL,
   PRIMARY KEY (alert_id),
-  FOREIGN KEY (alert_id) REFERENCES ambari.alert_history(alert_id)
+  FOREIGN KEY (definition_id) REFERENCES ambari.alert_definition(definition_id),
+  FOREIGN KEY (history_id) REFERENCES ambari.alert_history(alert_id)
 );
 
 CREATE TABLE ambari.alert_group (
@@ -288,15 +291,17 @@ CREATE TABLE ambari.alert_target (
 CREATE TABLE ambari.alert_group_target (
   group_id BIGINT NOT NULL,
   target_id BIGINT NOT NULL,
+  PRIMARY KEY (group_id, target_id),
   FOREIGN KEY (group_id) REFERENCES ambari.alert_group(group_id),
-  FOREIGN KEY (target_id) REFERENCES ambari.alert_target(target_id)
+  FOREIGN KEY (target_id) REFERENCES ambari.alert_target(target_id)  
 );
 
 CREATE TABLE ambari.alert_grouping (
   definition_id BIGINT NOT NULL,
   group_id BIGINT NOT NULL,
+  PRIMARY KEY (group_id, definition_id),
   FOREIGN KEY (definition_id) REFERENCES ambari.alert_definition(definition_id),
-  FOREIGN KEY (group_id) REFERENCES ambari.alert_group(group_id)
+  FOREIGN KEY (group_id) REFERENCES ambari.alert_group(group_id)  
 );
 
 CREATE TABLE ambari.alert_notice (
@@ -318,12 +323,13 @@ GRANT ALL PRIVILEGES ON TABLE ambari.alert_group_target TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.alert_grouping TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.alert_notice TO :username;
 
-
+CREATE INDEX idx_alert_history_def_id on ambari.alert_history(alert_definition_id);
 CREATE INDEX idx_alert_history_service on ambari.alert_history(service_name);
 CREATE INDEX idx_alert_history_host on ambari.alert_history(host_name);
 CREATE INDEX idx_alert_history_time on ambari.alert_history(alert_timestamp);
 CREATE INDEX idx_alert_history_state on ambari.alert_history(alert_state);
 CREATE INDEX idx_alert_group_name on ambari.alert_group(group_name);
+CREATE INDEX idx_alert_notice_state on ambari.alert_notice(notify_state);
 
 ---------inserting some data-----------
 BEGIN;
@@ -370,7 +376,9 @@ INSERT INTO ambari.ambari_sequences (sequence_name, "value")
   union all
   select 'alert_history_id_seq', 0
   union all
-  select 'alert_notice_id_seq', 0;
+  select 'alert_notice_id_seq', 0,
+  union all
+  select 'alert_current_id_seq', 0;
   
 
 INSERT INTO ambari.adminresourcetype (resource_type_id, resource_type_name)

+ 2 - 2
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java

@@ -181,7 +181,7 @@ public class AlertDefinitionResourceProviderTest {
     Assert.assertEquals("my_def", entity.getDefinitionName());
     Assert.assertTrue(entity.getEnabled());
     Assert.assertNotNull(entity.getHash());
-    Assert.assertEquals(Long.valueOf(1), entity.getScheduleInterval());
+    Assert.assertEquals(Integer.valueOf(1), entity.getScheduleInterval());
     Assert.assertNull(entity.getScope());
     Assert.assertEquals("HDFS", entity.getServiceName());
     Assert.assertNotNull(entity.getSource());
@@ -321,7 +321,7 @@ public class AlertDefinitionResourceProviderTest {
     entity.setDefinitionName("my_def");
     entity.setEnabled(true);
     entity.setHash("tmphash");
-    entity.setScheduleInterval(Long.valueOf(2L));
+    entity.setScheduleInterval(Integer.valueOf(2));
     entity.setServiceName(null);
     entity.setSourceType("metric");
     entity.setSource("{'jmx': 'beanName/attributeName', 'host': '{{aa:123445}}'}");

+ 76 - 0
ambari-server/src/test/java/org/apache/ambari/server/orm/OrmTestHelper.java

@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 import javax.persistence.EntityManager;
 
@@ -31,6 +32,7 @@ import org.apache.ambari.server.Role;
 import org.apache.ambari.server.RoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.AlertDispatchDAO;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
@@ -38,6 +40,9 @@ import org.apache.ambari.server.orm.dao.RequestDAO;
 import org.apache.ambari.server.orm.dao.RoleDAO;
 import org.apache.ambari.server.orm.dao.StageDAO;
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertTargetEntity;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterServiceEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
@@ -50,6 +55,7 @@ import org.apache.ambari.server.orm.entities.RoleEntity;
 import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.alert.Scope;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.util.Assert;
 
@@ -265,4 +271,74 @@ public class OrmTestHelper {
     Assert.isTrue(clusterEntity.getClusterId() > 0);
     return clusterEntity.getClusterId();
   }
+
+  /**
+   * Creates an alert target.
+   * 
+   * @return
+   */
+  @Transactional
+  public AlertTargetEntity createAlertTarget() throws Exception {
+    AlertTargetEntity target = new AlertTargetEntity();
+    target.setDescription("Target Description");
+    target.setNotificationType("EMAIL");
+    target.setProperties("Target Properties");
+    target.setTargetName("Target Name " + System.currentTimeMillis());
+
+    AlertDispatchDAO dao = injector.getInstance(AlertDispatchDAO.class);
+    dao.create(target);
+
+    return dao.findTargetById(target.getTargetId());
+  }
+  
+  /**
+   * Creates an alert definition.
+   * 
+   * @param clusterId
+   * @return
+   * @throws Exception
+   */
+  @Transactional
+  public AlertDefinitionEntity createAlertDefinition(long clusterId)
+      throws Exception {
+    AlertDefinitionEntity definition = new AlertDefinitionEntity();
+    definition.setDefinitionName("Alert Definition "
+        + System.currentTimeMillis());
+    definition.setServiceName("Service " + System.currentTimeMillis());
+    definition.setComponentName(null);
+    definition.setClusterId(clusterId);
+    definition.setHash(UUID.randomUUID().toString());
+    definition.setScheduleInterval(60);
+    definition.setScope(Scope.SERVICE);
+    definition.setSource("Source " + System.currentTimeMillis());
+    definition.setSourceType("SCRIPT");
+    
+    AlertDefinitionDAO dao = injector.getInstance(AlertDefinitionDAO.class);
+    dao.create(definition);
+
+    return dao.findById(definition.getDefinitionId());
+  }
+
+  /**
+   * Creates an alert group.
+   * 
+   * @param clusterId
+   * @param targets
+   * @return
+   * @throws Exception
+   */
+  @Transactional
+  public AlertGroupEntity createAlertGroup(long clusterId,
+      Set<AlertTargetEntity> targets) throws Exception {
+    AlertGroupEntity group = new AlertGroupEntity();
+    group.setDefault(false);
+    group.setGroupName("Group Name " + System.currentTimeMillis());
+    group.setClusterId(clusterId);
+    group.setAlertTargets(targets);
+
+    AlertDispatchDAO dao = injector.getInstance(AlertDispatchDAO.class);
+    dao.create(group);
+
+    return dao.findGroupById(group.getGroupId());
+  }
 }

+ 116 - 32
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java

@@ -24,10 +24,16 @@ import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 
+import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
+import java.util.TimeZone;
 import java.util.UUID;
 
 import javax.persistence.EntityManager;
@@ -36,7 +42,15 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
+import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertGroupEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertNoticeEntity;
+import org.apache.ambari.server.state.AlertState;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.NotificationState;
+import org.apache.ambari.server.state.alert.Scope;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
@@ -54,21 +68,30 @@ import com.google.inject.persist.PersistService;
  */
 @SuppressWarnings("unchecked")
 public class AlertDefinitionDAOTest {
+  static Injector injector;
+  static Long clusterId;
+  static AlertDefinitionDAO dao;
+  static AlertsDAO alertsDao;
+  static AlertDispatchDAO dispatchDao;
+  static OrmTestHelper helper;
+  static Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
 
-  AlertDefinitionDAO realDAO;
   AlertDefinitionDAO mockDAO;
   Provider<EntityManager> mockEntityManagerProvider = createStrictMock(Provider.class);
   EntityManager entityManager = createStrictMock(EntityManager.class);
 
-  private static Injector injector;
-  private static Long clusterId;
-
+  /**
+   * 
+   */
   @BeforeClass
   public static void beforeClass() {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
-    AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
-    clusterId = injector.getInstance(OrmTestHelper.class).createCluster();
+    dao = injector.getInstance(AlertDefinitionDAO.class);
+    alertsDao = injector.getInstance(AlertsDAO.class);
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
+    helper = injector.getInstance(OrmTestHelper.class);
+    clusterId = helper.createCluster();
 
     for (int i = 0; i < 8; i++) {
       AlertDefinitionEntity definition = new AlertDefinitionEntity();
@@ -77,11 +100,11 @@ public class AlertDefinitionDAOTest {
       definition.setComponentName(null);
       definition.setClusterId(clusterId);
       definition.setHash(UUID.randomUUID().toString());
-      definition.setScheduleInterval(60L);
-      definition.setScope("SERVICE");
+      definition.setScheduleInterval(60);
+      definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
       definition.setSourceType("SCRIPT");
-      alertDefinitionDAO.create(definition);
+      dao.create(definition);
     }
   }
 
@@ -95,7 +118,7 @@ public class AlertDefinitionDAOTest {
    * 
    */
   @Before
-  public void init() {
+  public void before() {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
     injector.injectMembers(this);
@@ -104,11 +127,7 @@ public class AlertDefinitionDAOTest {
     expect(mockEntityManagerProvider.get()).andReturn(entityManager).atLeastOnce();
     replay(mockEntityManagerProvider);
 
-    realDAO = new AlertDefinitionDAO();
-    mockDAO = new AlertDefinitionDAO();
-    injector.injectMembers(realDAO);
-    injector.injectMembers(mockDAO);
-
+    mockDAO = injector.getInstance(AlertDefinitionDAO.class);
     mockDAO.entityManagerProvider = mockEntityManagerProvider;
   }
 
@@ -139,10 +158,10 @@ public class AlertDefinitionDAOTest {
     assertSame(result, entity);
     verify(mockEntityManagerProvider, entityManager);
 
-    List<AlertDefinitionEntity> definitions = realDAO.findAll();
+    List<AlertDefinitionEntity> definitions = dao.findAll();
     Assert.assertNotNull(definitions);
     AlertDefinitionEntity definition = definitions.get(2);
-    AlertDefinitionEntity retrieved = realDAO.findByName(
+    AlertDefinitionEntity retrieved = dao.findByName(
         definition.getClusterId(), definition.getDefinitionName());
 
     Assert.assertEquals(definition, retrieved);
@@ -170,7 +189,7 @@ public class AlertDefinitionDAOTest {
     assertSame(entity, entities.get(0));
     verify(mockEntityManagerProvider, entityManager);
 
-    List<AlertDefinitionEntity> definitions = realDAO.findAll();
+    List<AlertDefinitionEntity> definitions = dao.findAll();
     Assert.assertNotNull(definitions);
     Assert.assertEquals(8, definitions.size());
   }
@@ -192,10 +211,10 @@ public class AlertDefinitionDAOTest {
     assertSame(result, entity);
     verify(mockEntityManagerProvider, entityManager);
 
-    List<AlertDefinitionEntity> definitions = realDAO.findAll();
+    List<AlertDefinitionEntity> definitions = dao.findAll();
     Assert.assertNotNull(definitions);
     AlertDefinitionEntity definition = definitions.get(2);
-    AlertDefinitionEntity retrieved = realDAO.findById(definition.getDefinitionId());
+    AlertDefinitionEntity retrieved = dao.findById(definition.getDefinitionId());
 
     Assert.assertEquals(definition, retrieved);
   }
@@ -244,18 +263,83 @@ public class AlertDefinitionDAOTest {
   }
 
   @Test
-  public void testRemove() {
-    AlertDefinitionEntity entity = new AlertDefinitionEntity();
-    AlertDefinitionEntity entity2 = new AlertDefinitionEntity();
-
-    // set expectations
-    expect(entityManager.merge(eq(entity))).andReturn(entity2);
-    entityManager.remove(eq(entity2));
-    replay(entityManager);
-
-    mockDAO.entityManagerProvider = mockEntityManagerProvider;
-    mockDAO.remove(entity);
+  public void testRemove() throws Exception {
+    AlertDefinitionEntity definition = helper.createAlertDefinition(clusterId);
+    definition = dao.findById(definition.getDefinitionId());
+    assertNotNull(definition);
+    dao.remove(definition);
+    definition = dao.findById(definition.getDefinitionId());
+    assertNull(definition);
+  }
 
-    verify(mockEntityManagerProvider, entityManager);
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testCascadeDelete() throws Exception {
+    AlertDefinitionEntity definition = helper.createAlertDefinition(clusterId);
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
+    group.getAlertDefinitions().add(definition);
+    dispatchDao.merge(group);
+
+    AlertHistoryEntity history = new AlertHistoryEntity();
+    history.setServiceName(definition.getServiceName());
+    history.setClusterId(clusterId);
+    history.setAlertDefinition(definition);
+    history.setAlertLabel("Label");
+    history.setAlertState(AlertState.OK);
+    history.setAlertText("Alert Text");
+    history.setAlertTimestamp(calendar.getTimeInMillis());
+    alertsDao.create(history);
+
+    AlertCurrentEntity current = new AlertCurrentEntity();
+    current.setAlertHistory(history);
+    current.setLatestTimestamp(new Date().getTime());
+    current.setOriginalTimestamp(new Date().getTime() - 10800000);
+    current.setMaintenanceState(MaintenanceState.OFF);
+    alertsDao.create(current);
+
+    AlertNoticeEntity notice = new AlertNoticeEntity();
+    notice.setAlertHistory(history);
+    notice.setAlertTarget(helper.createAlertTarget());
+    notice.setNotifyState(NotificationState.PENDING);
+    dispatchDao.create(notice);
+
+    group = dispatchDao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+    assertNotNull(group.getAlertDefinitions());
+    assertEquals(1, group.getAlertDefinitions().size());
+
+    history = alertsDao.findById(history.getAlertId());
+    assertNotNull(history);
+
+    current = alertsDao.findCurrentById(current.getAlertId());
+    assertNotNull(current);
+    assertNotNull(current.getAlertHistory());
+
+    notice = dispatchDao.findNoticeById(notice.getNotificationId());
+    assertNotNull(notice);
+    assertNotNull(notice.getAlertHistory());
+    assertNotNull(notice.getAlertTarget());
+
+    // delete the definition
+    definition = dao.findById(definition.getDefinitionId());
+    dao.refresh(definition);
+    dao.remove(definition);
+
+    notice = dispatchDao.findNoticeById(notice.getNotificationId());
+    assertNull(notice);
+
+    current = alertsDao.findCurrentById(current.getAlertId());
+    assertNull(current);
+
+    history = alertsDao.findById(history.getAlertId());
+    assertNull(history);
+
+    group = dispatchDao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+    assertNotNull(group.getAlertDefinitions());
+    assertEquals(0, group.getAlertDefinitions().size());
   }
 }

+ 249 - 21
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDispatchDAOTest.java

@@ -18,17 +18,26 @@
 
 package org.apache.ambari.server.orm.dao;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.OrmTestHelper;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertGroupEntity;
 import org.apache.ambari.server.orm.entities.AlertTargetEntity;
+import org.apache.ambari.server.state.alert.Scope;
 import org.junit.AfterClass;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -44,14 +53,21 @@ public class AlertDispatchDAOTest {
 
   static Long clusterId;
   static Injector injector;
-  AlertDispatchDAO dao;
+  static AlertDispatchDAO dao;
+  static OrmTestHelper helper;
+
+  AlertDefinitionDAO definitionDao;
 
+  /**
+   * 
+   */
   @BeforeClass
   public static void beforeClass() {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
-    clusterId = injector.getInstance(OrmTestHelper.class).createCluster();
-    AlertDispatchDAO alertDispatchDAO = injector.getInstance(AlertDispatchDAO.class);
+    helper = injector.getInstance(OrmTestHelper.class);
+    clusterId = helper.createCluster();
+    dao = injector.getInstance(AlertDispatchDAO.class);
 
     Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
     for (int i = 0; i < 5; i++) {
@@ -60,7 +76,7 @@ public class AlertDispatchDAOTest {
       target.setNotificationType("EMAIL");
       target.setProperties("Target Properties " + i);
       target.setTargetName("Target Name " + i);
-      alertDispatchDAO.create(target);
+      dao.create(target);
       targets.add(target);
     }
 
@@ -70,9 +86,8 @@ public class AlertDispatchDAOTest {
       group.setGroupName("Group Name " + i);
       group.setClusterId(clusterId);
       group.setAlertTargets(targets);
-      alertDispatchDAO.create(group);
+      dao.create(group);
     }
-
   }
 
   /**
@@ -89,56 +104,269 @@ public class AlertDispatchDAOTest {
    */
   @Before
   public void setup() {
-    dao = new AlertDispatchDAO();
-    injector.injectMembers(dao);
+    definitionDao = injector.getInstance(AlertDefinitionDAO.class);
   }
 
   /**
    * 
    */
   @Test
-  public void testFindAllTargets() {
+  public void testFindAllTargets() throws Exception {
     List<AlertTargetEntity> targets = dao.findAllTargets();
-    Assert.assertNotNull(targets);
-    Assert.assertEquals(5, targets.size());
+    assertNotNull(targets);
+    assertEquals(5, targets.size());
   }
 
   /**
    * 
    */
   @Test
-  public void testFindTargetByName() {
+  public void testFindTargetByName() throws Exception {
     List<AlertTargetEntity> targets = dao.findAllTargets();
-    Assert.assertNotNull(targets);
+    assertNotNull(targets);
     AlertTargetEntity target = targets.get(3);
 
     AlertTargetEntity actual = dao.findTargetByName(target.getTargetName());
-    Assert.assertEquals(target, actual);
+    assertEquals(target, actual);
   }
 
   /**
    * 
    */
   @Test
-  public void testFindAllGroups() {
+  public void testFindAllGroups() throws Exception {
     List<AlertGroupEntity> groups = dao.findAllGroups();
-    Assert.assertNotNull(groups);
-    Assert.assertEquals(10, groups.size());
+    assertNotNull(groups);
+    assertEquals(10, groups.size());
   }
 
   /**
    * 
    */
   @Test
-  public void testFindGroupByName() {
+  public void testFindGroupByName() throws Exception {
     List<AlertGroupEntity> groups = dao.findAllGroups();
-    Assert.assertNotNull(groups);
+    assertNotNull(groups);
     AlertGroupEntity group = groups.get(3);
 
     AlertGroupEntity actual = dao.findGroupByName(group.getClusterId(),
         group.getGroupName());
 
-    Assert.assertEquals(group, actual);
+    assertEquals(group, actual);
   }
 
+  /**
+   * 
+   */
+  @Test
+  public void testCreateGroup() throws Exception {
+    AlertTargetEntity target = helper.createAlertTarget();
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, targets);
+    AlertGroupEntity actual = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+
+    assertEquals(group.getGroupName(), actual.getGroupName());
+    assertEquals(group.isDefault(), actual.isDefault());
+    assertEquals(group.getAlertTargets(), actual.getAlertTargets());
+    assertEquals(group.getAlertDefinitions(), actual.getAlertDefinitions());
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testGroupDefinitions() throws Exception {
+    List<AlertDefinitionEntity> definitions = createDefinitions();
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+
+    group.getAlertDefinitions().addAll(definitions);
+    dao.merge(group);
+
+    group = dao.findGroupByName(group.getGroupName());
+    assertEquals(definitions.size(), group.getAlertDefinitions().size());
+
+    for (AlertDefinitionEntity definition : definitions) {
+      assertTrue(group.getAlertDefinitions().contains(definition));
+    }
+
+    definitionDao.refresh(definitions.get(0));
+    definitionDao.remove(definitions.get(0));
+    definitions.remove(0);
+
+    group = dao.findGroupByName(group.getGroupName());
+    assertEquals(definitions.size(), group.getAlertDefinitions().size());
+
+    for (AlertDefinitionEntity definition : definitions) {
+      assertTrue(group.getAlertDefinitions().contains(definition));
+    }
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testCreateTarget() throws Exception {
+    int targetCount = dao.findAllTargets().size();
+
+    AlertTargetEntity target = helper.createAlertTarget();
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, targets);
+    AlertTargetEntity actual = dao.findTargetById(target.getTargetId());
+    assertNotNull(actual);
+
+    assertEquals(target.getTargetName(), actual.getTargetName());
+    assertEquals(target.getDescription(), actual.getDescription());
+    assertEquals(target.getNotificationType(), actual.getNotificationType());
+    assertEquals(target.getProperties(), actual.getProperties());
+
+    assertNotNull(actual.getAlertGroups());
+    Iterator<AlertGroupEntity> iterator = actual.getAlertGroups().iterator();
+    AlertGroupEntity actualGroup = iterator.next();
+
+    assertEquals(group, actualGroup);
+
+    assertEquals(targetCount + 1, dao.findAllTargets().size());
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testDeleteGroup() throws Exception {
+    int targetCount = dao.findAllTargets().size();    
+    
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
+    AlertTargetEntity target = helper.createAlertTarget();
+    assertEquals(targetCount + 1, dao.findAllTargets().size());
+
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+    assertNotNull(group.getAlertTargets());
+    assertEquals(0, group.getAlertTargets().size());
+
+    group.setAlertTargets(targets);
+    dao.merge(group);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+    assertNotNull(group.getAlertTargets());
+    assertEquals(1, group.getAlertTargets().size());
+
+    dao.remove(group);
+    group = dao.findGroupById(group.getGroupId());
+    assertNull(group);
+
+    target = dao.findTargetById(target.getTargetId());
+    assertNotNull(target);
+    assertEquals(targetCount + 1, dao.findAllTargets().size());
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testDeleteTarget() throws Exception {
+    AlertTargetEntity target = helper.createAlertTarget();
+    target = dao.findTargetById(target.getTargetId());
+    assertNotNull(target);
+
+    dao.remove(target);
+
+    target = dao.findTargetById(target.getTargetId());
+    assertNull(target);
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testDeleteAssociatedTarget() throws Exception {
+    AlertTargetEntity target = helper.createAlertTarget();
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, targets);
+
+    target = dao.findTargetById(target.getTargetId());
+    assertNotNull(target);
+
+    dao.remove(target);
+    target = dao.findTargetById(target.getTargetId());
+    assertNull(target);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertNotNull(group);
+
+    assertEquals(0, group.getAlertTargets().size());
+  }
+
+  /**
+   * 
+   */
+  @Test
+  public void testUpdateGroup() throws Exception {
+    AlertTargetEntity target = helper.createAlertTarget();
+    Set<AlertTargetEntity> targets = new HashSet<AlertTargetEntity>();
+    targets.add(target);
+
+    String groupName = "Group Name " + System.currentTimeMillis();
+
+    AlertGroupEntity group = helper.createAlertGroup(clusterId, null);
+
+    group = dao.findGroupById(group.getGroupId());
+    group.setGroupName(groupName + "FOO");
+    group.setDefault(true);
+
+    dao.merge(group);
+    group = dao.findGroupById(group.getGroupId());
+
+    assertEquals(groupName + "FOO", group.getGroupName());
+    assertEquals(true, group.isDefault());
+    assertNotNull(group.getAlertDefinitions());
+    assertNotNull(group.getAlertTargets());
+    assertEquals(0, group.getAlertDefinitions().size());
+    assertEquals(0, group.getAlertTargets().size());
+
+    group.getAlertTargets().add(target);
+    dao.merge(group);
+
+    group = dao.findGroupById(group.getGroupId());
+    assertEquals(targets, group.getAlertTargets());
+  }
+
+  /**
+   * @return
+   */
+  private List<AlertDefinitionEntity> createDefinitions() throws Exception {
+    List<AlertDefinitionEntity> alertDefinitions = new ArrayList<AlertDefinitionEntity>();
+
+    for (int i = 0; i < 8; i++) {
+      AlertDefinitionEntity definition = new AlertDefinitionEntity();
+      definition.setDefinitionName("Alert Definition " + i);
+      definition.setServiceName("HDFS");
+      definition.setComponentName(null);
+      definition.setClusterId(clusterId);
+      definition.setHash(UUID.randomUUID().toString());
+      definition.setScheduleInterval(60);
+      definition.setScope(Scope.SERVICE);
+      definition.setSource("Source " + i);
+      definition.setSourceType("SCRIPT");
+      definitionDao.create(definition);
+      alertDefinitions.add(definition);
+    }
+
+    return alertDefinitions;
+  }
 }

+ 31 - 27
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java

@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.orm.dao;
 
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
@@ -37,6 +38,7 @@ import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
 import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.alert.Scope;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -54,16 +56,23 @@ public class AlertsDAOTest {
   static Long clusterId;
   static Injector injector;
   static Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+  static OrmTestHelper helper;
+  static AlertsDAO dao;
+  static AlertDefinitionDAO definitionDao;
+  static AlertDispatchDAO dispatchDao;
 
-  AlertsDAO dao;
-
+  /**
+   * 
+   */
   @BeforeClass
   public static void beforeClass() {
     injector = Guice.createInjector(new InMemoryDefaultTestModule());
     injector.getInstance(GuiceJpaInitializer.class);
-    clusterId = injector.getInstance(OrmTestHelper.class).createCluster();
-    AlertsDAO alertDAO = injector.getInstance(AlertsDAO.class);
-    AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
+    helper = injector.getInstance(OrmTestHelper.class);
+    clusterId = helper.createCluster();
+    dao = injector.getInstance(AlertsDAO.class);
+    definitionDao = injector.getInstance(AlertDefinitionDAO.class);
+    dispatchDao = injector.getInstance(AlertDispatchDAO.class);
 
     // create 5 definitions
     for (int i = 0; i < 5; i++) {
@@ -73,14 +82,14 @@ public class AlertsDAOTest {
       definition.setComponentName(null);
       definition.setClusterId(clusterId);
       definition.setHash(UUID.randomUUID().toString());
-      definition.setScheduleInterval(60L);
-      definition.setScope("SERVICE");
+      definition.setScheduleInterval(60);
+      definition.setScope(Scope.SERVICE);
       definition.setSource("Source " + i);
       definition.setSourceType("SCRIPT");
-      alertDefinitionDAO.create(definition);
+      definitionDao.create(definition);
     }
 
-    List<AlertDefinitionEntity> definitions = alertDefinitionDAO.findAll();
+    List<AlertDefinitionEntity> definitions = definitionDao.findAll();
     assertNotNull(definitions);
     assertEquals(5, definitions.size());
 
@@ -95,26 +104,24 @@ public class AlertsDAOTest {
         history.setClusterId(clusterId);
         history.setAlertDefinition(definition);
         history.setAlertLabel(definition.getDefinitionName() + " " + i);
-        history.setAlertState(AlertState.OK);
         history.setAlertText(definition.getDefinitionName() + " " + i);
         history.setAlertTimestamp(calendar.getTimeInMillis());
 
+        history.setAlertState(AlertState.OK);
+        if (i == 0 || i == 5) {
+          history.setAlertState(AlertState.CRITICAL);
+        }
+
         // increase the days for each
         calendar.add(Calendar.DATE, 1);
 
-        alertDAO.create(history);
-
-        if (i == 0 || i == 1) {
-          history.setAlertId(null);
-          history.setAlertState(AlertState.CRITICAL);
-          alertDAO.create(history);
-        }
+        dao.create(history);
       }
     }
 
     // for each definition, create a current alert
     for (AlertDefinitionEntity definition : definitions) {
-      List<AlertHistoryEntity> alerts = alertDAO.findAll();
+      List<AlertHistoryEntity> alerts = dao.findAll();
       AlertHistoryEntity history = null;
       for (AlertHistoryEntity alert : alerts) {
         if (definition.equals(alert.getAlertDefinition())) {
@@ -125,12 +132,11 @@ public class AlertsDAOTest {
       assertNotNull(history);
 
       AlertCurrentEntity current = new AlertCurrentEntity();
-      current.setAlertId(history.getAlertId());
       current.setAlertHistory(history);
       current.setLatestTimestamp(new Date().getTime());
       current.setOriginalTimestamp(new Date().getTime() - 10800000);
       current.setMaintenanceState(MaintenanceState.OFF);
-      alertDAO.create(current);
+      dao.create(current);
     }
   }
 
@@ -148,8 +154,6 @@ public class AlertsDAOTest {
    */
   @Before
   public void setup() {
-    dao = new AlertsDAO();
-    injector.injectMembers(dao);
   }
 
   /**
@@ -159,7 +163,7 @@ public class AlertsDAOTest {
   public void testFindAll() {
     List<AlertHistoryEntity> alerts = dao.findAll(clusterId);
     assertNotNull(alerts);
-    assertEquals(60, alerts.size());
+    assertEquals(50, alerts.size());
   }
 
   /**
@@ -207,11 +211,11 @@ public class AlertsDAOTest {
         
     List<AlertHistoryEntity> history = dao.findAll(clusterId, allStates);
     assertNotNull(history);
-    assertEquals(60, history.size());
+    assertEquals(50, history.size());
 
     history = dao.findAll(clusterId, Collections.singletonList(AlertState.OK));
     assertNotNull(history);
-    assertEquals(50, history.size());
+    assertEquals(40, history.size());
 
     history = dao.findAll(clusterId,
         Collections.singletonList(AlertState.CRITICAL));
@@ -237,12 +241,12 @@ public class AlertsDAOTest {
         calendar.getTime(), null);
 
     assertNotNull(history);
-    assertEquals(60, history.size());
+    assertEquals(50, history.size());
 
     // on or before 1/1/2014
     history = dao.findAll(clusterId, null, calendar.getTime());
     assertNotNull(history);
-    assertEquals(2, history.size());
+    assertEquals(1, history.size());
 
     // between 1/5 and 1/10
     calendar.set(2014, Calendar.JANUARY, 5);