Przeglądaj źródła

AMBARI-7734 - Alerts: Create REST API Endpoint for Alert History (jonathanhurley)

Jonathan Hurley 10 lat temu
rodzic
commit
03784ecad8
24 zmienionych plików z 1433 dodań i 83 usunięć
  1. 258 0
      ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java
  2. 50 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertHistoryResourceDefinition.java
  3. 5 1
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
  4. 99 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.java
  5. 20 2
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java
  6. 34 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/AlertHistoryRequest.java
  7. 2 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
  8. 0 6
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
  9. 37 4
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
  10. 28 8
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java
  11. 251 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertHistoryResourceProvider.java
  12. 26 11
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java
  13. 11 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
  14. 2 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
  15. 67 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java
  16. 50 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity_.java
  17. 94 0
      ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity_.java
  18. 0 11
      ambari-server/src/main/resources/key_properties.json
  19. 0 29
      ambari-server/src/main/resources/properties.json
  20. 1 4
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
  21. 1 3
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java
  22. 228 0
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertHistoryResourceProviderTest.java
  23. 1 3
      ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java
  24. 168 0
      ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java

+ 258 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/query/JpaPredicateVisitor.java

@@ -0,0 +1,258 @@
+/**
+ * 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.api.query;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
+import org.apache.ambari.server.controller.predicate.ArrayPredicate;
+import org.apache.ambari.server.controller.predicate.CategoryPredicate;
+import org.apache.ambari.server.controller.predicate.ComparisonPredicate;
+import org.apache.ambari.server.controller.predicate.PredicateVisitor;
+import org.apache.ambari.server.controller.predicate.UnaryPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
+
+/**
+ * The {@link JpaPredicateVisitor} is used to convert an Ambari
+ * {@link Predicate} into a JPA {@link javax.persistence.criteria.Predicate}.
+ */
+public abstract class JpaPredicateVisitor<T> implements PredicateVisitor {
+  /**
+   * JPA entity manager
+   */
+  private EntityManager m_entityManager;
+
+  /**
+   * Builds the {@link CriteriaQuery} from the {@link Predicate}.
+   */
+  private CriteriaBuilder m_builder;
+
+  /**
+   * The root that the {@code from} clause requests from.
+   */
+  private Root<T> m_root;
+
+  /**
+   * The query to submit to JPA.
+   */
+  private CriteriaQuery<T> m_query;
+
+  /**
+   * The last calculated predicate.
+   */
+  private javax.persistence.criteria.Predicate m_lastPredicate = null;
+
+  /**
+   * A queue of lists of {@link javax.persistence.criteria.Predicate}. Every
+   * time an {@code OR} or {@code AND} is encountered, a new chain (list) is
+   * created and the prior list is enqeued. When the logical statement is
+   * closed, the chain is completed and added to the prior chain's list.
+   */
+  private ArrayDeque<List<javax.persistence.criteria.Predicate>> m_queue =
+      new ArrayDeque<List<javax.persistence.criteria.Predicate>>();
+
+  /**
+   * Constructor.
+   *
+   * @param entityManager
+   *          the EM used to get a {@link CriteriaBuilder}.
+   * @param entityClass
+   *          the entity class being queried from.
+   */
+  public JpaPredicateVisitor(EntityManager entityManager, Class<T> entityClass) {
+    m_entityManager = entityManager;
+    m_builder = m_entityManager.getCriteriaBuilder();
+    m_query = m_builder.createQuery(entityClass);
+    m_root = m_query.from(entityClass);
+  }
+
+  /**
+   * Gets the entity class that is the root type in the JPA {@code from} clause.
+   *
+   * @return the entity class (not {@code null}).
+   */
+  public abstract Class<T> getEntityClass();
+
+  /**
+   * Gets the {@link SingularAttribute}s mapped to the specified Ambari-style
+   * property.
+   *
+   * @param propertyId
+   *          the Ambari-style property (not {@code null}).
+   * @return the {@link SingularAttribute}, or {@code null} if no mapping
+   *         exists.
+   */
+  public abstract List<? extends SingularAttribute<?, ?>> getPredicateMapping(
+      String propertyId);
+
+  /**
+   * Gets the final JPA {@link javax.persistence.criteria.Predicate} after the
+   * visitor is done traversing the Ambari {@link Predicate}.
+   *
+   * @return the predicate, or {@code null} if none.
+   */
+  public javax.persistence.criteria.Predicate getJpaPredicate() {
+    return m_lastPredicate;
+  }
+
+  /**
+   * Gets the query to use along with {@link #getJpaPredicate()}.
+   *
+   * @return the query (not {@code null}).
+   */
+  public CriteriaQuery<T> getCriteriaQuery() {
+    return m_query;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings({ "unchecked", "rawtypes" })
+  public void acceptComparisonPredicate(ComparisonPredicate predicate) {
+    String propertyId = predicate.getPropertyId();
+
+    List<? extends SingularAttribute<?, ?>> singularAttributes = getPredicateMapping(propertyId);
+
+    if (null == singularAttributes || singularAttributes.size() == 0) {
+      return;
+    }
+
+    SingularAttribute<?, ?> lastSingularAttribute = null;
+    Path<Comparable> path = null;
+
+    for (SingularAttribute<?, ?> singularAttribute : singularAttributes) {
+      lastSingularAttribute = singularAttribute;
+
+      if (null == path) {
+        path = m_root.get(singularAttribute.getName());
+      } else {
+        path = path.get(singularAttribute.getName());
+      }
+    }
+
+    if (null == path) {
+      return;
+    }
+
+    String operator = predicate.getOperator();
+    Comparable<?> value = predicate.getValue();
+
+    // convert string to enum for proper JPA comparisons
+    Class<?> clazz = lastSingularAttribute.getJavaType();
+    if (clazz.isEnum()) {
+      Class<? extends Enum> enumClass = (Class<? extends Enum>) clazz;
+      value = Enum.valueOf(enumClass, value.toString());
+    }
+
+    javax.persistence.criteria.Predicate jpaPredicate = null;
+    if ("=".equals(operator)) {
+      jpaPredicate = m_builder.equal(path, value);
+    } else if ("<".equals(operator)) {
+      jpaPredicate = m_builder.lessThan(path, value);
+    } else if ("<=".equals(operator)) {
+      jpaPredicate = m_builder.lessThanOrEqualTo(path, value);
+    } else if (">".equals(operator)) {
+      jpaPredicate = m_builder.greaterThan(path, value);
+    } else if (">=".equals(operator)) {
+      jpaPredicate = m_builder.greaterThanOrEqualTo(path, value);
+    }
+
+    if (null == jpaPredicate) {
+      return;
+    }
+
+    if (null == m_queue.peekLast()) {
+      m_lastPredicate = jpaPredicate;
+    } else {
+      m_queue.peekLast().add(jpaPredicate);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptArrayPredicate(ArrayPredicate predicate) {
+    // no predicates, no work
+    Predicate[] predicates = predicate.getPredicates();
+    if (predicates.length == 0) {
+      return;
+    }
+
+    // create a new list for all of the predicates in this chain
+    List<javax.persistence.criteria.Predicate> predicateList = new ArrayList<javax.persistence.criteria.Predicate>();
+    m_queue.add(predicateList);
+
+    // visit every child predicate so it can be added to the list
+    String operator = predicate.getOperator();
+    for (int i = 0; i < predicates.length; i++) {
+      PredicateHelper.visit(predicates[i], this);
+    }
+
+    // the list is done; deque and apply logical AND or OR
+    predicateList = m_queue.pollLast();
+
+    javax.persistence.criteria.Predicate jpaPredicate = null;
+    javax.persistence.criteria.Predicate[] array = new javax.persistence.criteria.Predicate[predicateList.size()];
+    array = predicateList.toArray(array);
+
+    if ("AND".equals(operator)) {
+      jpaPredicate = m_builder.and(array);
+    } else {
+      jpaPredicate = m_builder.or(array);
+    }
+
+    if (null == m_queue.peekLast()) {
+      m_lastPredicate = jpaPredicate;
+    } else {
+      m_queue.peekLast().add(jpaPredicate);
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptUnaryPredicate(UnaryPredicate predicate) {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptAlwaysPredicate(AlwaysPredicate predicate) {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void acceptCategoryPredicate(CategoryPredicate predicate) {
+  }
+}

+ 50 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/AlertHistoryResourceDefinition.java

@@ -0,0 +1,50 @@
+/**
+ * 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.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Resource Definition for {@link Resource.Type#AlertHistory} types.
+ */
+public class AlertHistoryResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * Constructor.
+   *
+   */
+  public AlertHistoryResourceDefinition() {
+    super(Resource.Type.AlertHistory);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getPluralName() {
+    return "alert_history";
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getSingularName() {
+    return "alert_history";
+  }
+}

+ 5 - 1
ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java

@@ -249,7 +249,7 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
       case Permission:
         resourceDefinition = new PermissionResourceDefinition();
         break;
-        
+
       case Alert:
         resourceDefinition = new AlertResourceDefinition();
         break;
@@ -258,6 +258,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new AlertDefResourceDefinition();
         break;
 
+      case AlertHistory:
+        resourceDefinition = new AlertHistoryResourceDefinition();
+        break;
+
       case AlertGroup:
         resourceDefinition = new AlertGroupResourceDefinition();
         break;

+ 99 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/AlertHistoryService.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.api.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * Endpoint for alert history.
+ */
+public class AlertHistoryService extends BaseService {
+
+  private String clusterName = null;
+  private String serviceName = null;
+  private String hostName = null;
+
+  /**
+   * Constructor.
+   *
+   * @param clusterName
+   *          the cluster name (not {@code null}).
+   * @param serviceName
+   *          the service name, or {@code null} to return history across all
+   *          services.
+   * @param hostName
+   *          the host name, or {@code null} to return history across all hosts.
+   */
+  AlertHistoryService(String clusterName, String serviceName, String hostName) {
+    this.clusterName = clusterName;
+    this.serviceName = serviceName;
+    this.hostName = hostName;
+  }
+
+  @GET
+  @Produces("text/plain")
+  public Response getHistories(String body,
+      @Context HttpHeaders headers,
+      @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createResourceInstance(clusterName, null));
+  }
+
+  @GET
+  @Path("{alertHistoryId}")
+  @Produces("text/plain")
+  public Response getHistory(String body,
+      @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("alertHistoryId") Long id) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createResourceInstance(clusterName, id));
+  }
+
+  /**
+   * Create an alert history resource instance
+   *
+   * @param clusterName
+   * @return
+   */
+  private ResourceInstance createResourceInstance(String clusterName,
+      Long historyId) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Cluster, clusterName);
+    mapIds.put(Resource.Type.Service, serviceName);
+    mapIds.put(Resource.Type.Host, hostName);
+
+    if (null != historyId) {
+      mapIds.put(Resource.Type.AlertHistory, historyId.toString());
+    }
+
+    return createResource(Resource.Type.AlertHistory, mapIds);
+  }
+}

+ 20 - 2
ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java

@@ -357,7 +357,7 @@ public class ClusterService extends BaseService {
     hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
     return new ClusterPrivilegeService(clusterName);
   }
-  
+
   /**
    * Gets the alert definition service
    *
@@ -372,8 +372,26 @@ public class ClusterService extends BaseService {
 
     hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
     return new AlertService(clusterName, null, null);
-  }  
+  }
 
+  /**
+   * Gets the alert history service
+   *
+   * @param request
+   *          the request
+   * @param clusterName
+   *          the cluster name
+   *
+   * @return the alert history service
+   */
+  @Path("{clusterName}/alert_history")
+  public AlertHistoryService getAlertHistoryService(
+      @Context javax.ws.rs.core.Request request,
+      @PathParam("clusterName") String clusterName) {
+
+    hasPermission(Request.Type.valueOf(request.getMethod()), clusterName);
+    return new AlertHistoryService(clusterName, null, null);
+  }
 
   // ----- helper methods ----------------------------------------------------
 

+ 34 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/AlertHistoryRequest.java

@@ -0,0 +1,34 @@
+/**
+ * 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.controller;
+
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+
+/**
+ * The {@link AlertHistoryRequest} encapsulates the data necessary to make a
+ * backend request for {@link AlertHistoryEntity}.
+ */
+public class AlertHistoryRequest {
+
+  /**
+   * An Ambari predicate.
+   */
+  public Predicate Predicate;
+
+}

+ 2 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java

@@ -47,6 +47,7 @@ import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.internal.AbstractControllerResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertGroupResourceProvider;
+import org.apache.ambari.server.controller.internal.AlertHistoryResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertResourceProvider;
 import org.apache.ambari.server.controller.internal.AlertSummaryPropertyProvider;
 import org.apache.ambari.server.controller.internal.AlertTargetResourceProvider;
@@ -577,6 +578,7 @@ public class AmbariServer {
     ClusterResourceProvider.init(injector.getInstance(BlueprintDAO.class), ambariMetaInfo, injector.getInstance(ConfigHelper.class));
     AlertResourceProvider.init(injector);
     AlertDefinitionResourceProvider.init(injector);
+    AlertHistoryResourceProvider.init(injector);
     AlertGroupResourceProvider.init(injector);
     AlertSummaryPropertyProvider.init(injector);
     AlertTargetResourceProvider.init(injector);

+ 0 - 6
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java

@@ -151,12 +151,6 @@ public abstract class AbstractControllerResourceProvider extends AbstractResourc
         return new ValidationResourceProvider(propertyIds, keyPropertyIds, managementController);
       case Alert:
         return new AlertResourceProvider(propertyIds, keyPropertyIds, managementController);
-      case AlertDefinition:
-        return new AlertDefinitionResourceProvider(propertyIds, keyPropertyIds, managementController);
-      case AlertGroup:
-        return new AlertGroupResourceProvider(propertyIds, keyPropertyIds, managementController);
-      case AlertTarget:
-        return new AlertTargetResourceProvider(propertyIds, keyPropertyIds, managementController);
       case ClientConfig:
         return new ClientConfigResourceProvider(propertyIds, keyPropertyIds, managementController);
       default:

+ 37 - 4
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java

@@ -20,6 +20,7 @@ package org.apache.ambari.server.controller.internal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -104,6 +105,35 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
    */
   private static ActionQueue actionQueue;
 
+  /**
+   * The property ids for an alert defintion resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<String>();
+
+  /**
+   * The key property ids for an alert definition resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(ALERT_DEF_CLUSTER_NAME);
+    PROPERTY_IDS.add(ALERT_DEF_SERVICE_NAME);
+    PROPERTY_IDS.add(ALERT_DEF_COMPONENT_NAME);
+    PROPERTY_IDS.add(ALERT_DEF_ID);
+    PROPERTY_IDS.add(ALERT_DEF_NAME);
+    PROPERTY_IDS.add(ALERT_DEF_LABEL);
+    PROPERTY_IDS.add(ALERT_DEF_INTERVAL);
+    PROPERTY_IDS.add(ALERT_DEF_ENABLED);
+    PROPERTY_IDS.add(ALERT_DEF_SCOPE);
+    PROPERTY_IDS.add(ALERT_DEF_SOURCE);
+    PROPERTY_IDS.add(ALERT_DEF_ACTION_RUN_NOW);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.AlertDefinition, ALERT_DEF_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.Cluster, ALERT_DEF_CLUSTER_NAME);
+  }
+
   /**
    * @param instance
    */
@@ -115,10 +145,13 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
     actionQueue = injector.getInstance(ActionQueue.class);
   }
 
-  AlertDefinitionResourceProvider(Set<String> propertyIds,
-      Map<Resource.Type, String> keyPropertyIds,
-      AmbariManagementController managementController) {
-    super(propertyIds, keyPropertyIds, managementController);
+  /**
+   * Constructor.
+   *
+   * @param controller
+   */
+  AlertDefinitionResourceProvider(AmbariManagementController controller) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
   }
 
   @Override

+ 28 - 8
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProvider.java

@@ -21,6 +21,7 @@ import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -35,7 +36,6 @@ import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
@@ -71,6 +71,30 @@ public class AlertGroupResourceProvider extends
   private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
       Arrays.asList(ALERT_GROUP_ID, ALERT_GROUP_CLUSTER_NAME));
 
+  /**
+   * The property ids for an alert group resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<String>();
+
+  /**
+   * The key property ids for an alert group resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(ALERT_GROUP_ID);
+    PROPERTY_IDS.add(ALERT_GROUP_CLUSTER_NAME);
+    PROPERTY_IDS.add(ALERT_GROUP_NAME);
+    PROPERTY_IDS.add(ALERT_GROUP_DEFAULT);
+    PROPERTY_IDS.add(ALERT_GROUP_DEFINITIONS);
+    PROPERTY_IDS.add(ALERT_GROUP_TARGETS);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.AlertGroup, ALERT_GROUP_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.Cluster, ALERT_GROUP_CLUSTER_NAME);
+  }
+
   /**
    * Group/Target DAO
    */
@@ -97,14 +121,10 @@ public class AlertGroupResourceProvider extends
   /**
    * Constructor.
    *
-   * @param propertyIds
-   * @param keyPropertyIds
-   * @param managementController
+   * @param controller
    */
-  AlertGroupResourceProvider(Set<String> propertyIds,
-      Map<Type, String> keyPropertyIds,
-      AmbariManagementController managementController) {
-    super(propertyIds, keyPropertyIds, managementController);
+  AlertGroupResourceProvider(AmbariManagementController controller) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
   }
 
   @Override

+ 251 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertHistoryResourceProvider.java

@@ -0,0 +1,251 @@
+/**
+ * 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.controller.internal;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AlertHistoryRequest;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.state.Cluster;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * ResourceProvider for Alert History
+ */
+public class AlertHistoryResourceProvider extends
+    AbstractControllerResourceProvider {
+
+  public static final String ALERT_HISTORY = "AlertHistory";
+  public static final String ALERT_HISTORY_DEFINITION_ID = "AlertHistory/definition_id";
+  public static final String ALERT_HISTORY_DEFINITION_NAME = "AlertHistory/definition_name";
+  public static final String ALERT_HISTORY_ID = "AlertHistory/id";
+  public static final String ALERT_HISTORY_CLUSTER_NAME = "AlertHistory/cluster_name";
+  public static final String ALERT_HISTORY_SERVICE_NAME = "AlertHistory/service_name";
+  public static final String ALERT_HISTORY_COMPONENT_NAME = "AlertHistory/component_name";
+  public static final String ALERT_HISTORY_HOSTNAME = "AlertHistory/host_name";
+  public static final String ALERT_HISTORY_LABEL = "AlertHistory/label";
+  public static final String ALERT_HISTORY_STATE = "AlertHistory/state";
+  public static final String ALERT_HISTORY_TEXT = "AlertHistory/text";
+  public static final String ALERT_HISTORY_TIMESTAMP = "AlertHistory/timestamp";
+  public static final String ALERT_HISTORY_INSTANCE = "AlertHistory/instance";
+
+  private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
+      Arrays.asList(ALERT_HISTORY_ID));
+
+  /**
+   * Used for querying alert history.
+   */
+  private static AlertsDAO s_dao = null;
+
+  /**
+   * The property ids for an alert history resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<String>();
+
+  /**
+   * The key property ids for an alert history resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS =
+      new HashMap<Resource.Type, String>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(ALERT_HISTORY_DEFINITION_ID);
+    PROPERTY_IDS.add(ALERT_HISTORY_DEFINITION_NAME);
+    PROPERTY_IDS.add(ALERT_HISTORY_ID);
+    PROPERTY_IDS.add(ALERT_HISTORY_CLUSTER_NAME);
+    PROPERTY_IDS.add(ALERT_HISTORY_SERVICE_NAME);
+    PROPERTY_IDS.add(ALERT_HISTORY_COMPONENT_NAME);
+    PROPERTY_IDS.add(ALERT_HISTORY_HOSTNAME);
+    PROPERTY_IDS.add(ALERT_HISTORY_LABEL);
+    PROPERTY_IDS.add(ALERT_HISTORY_STATE);
+    PROPERTY_IDS.add(ALERT_HISTORY_TEXT);
+    PROPERTY_IDS.add(ALERT_HISTORY_TIMESTAMP);
+    PROPERTY_IDS.add(ALERT_HISTORY_INSTANCE);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.AlertHistory, ALERT_HISTORY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.Cluster, ALERT_HISTORY_CLUSTER_NAME);
+  }
+
+  /**
+   * Static intializer for Guice.
+   *
+   * @param instance
+   */
+  @Inject
+  public static void init(Injector injector) {
+    s_dao = injector.getInstance(AlertsDAO.class);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param controller
+   */
+  AlertHistoryResourceProvider(AmbariManagementController controller) {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return PK_PROPERTY_IDS;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException,
+      UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    Cluster cluster = null;
+    Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
+    Set<Resource> results = new LinkedHashSet<Resource>();
+
+    Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+    for (Map<String, Object> propertyMap : propertyMaps) {
+      String clusterName = (String) propertyMap.get(ALERT_HISTORY_CLUSTER_NAME);
+
+      if (null == clusterName || clusterName.isEmpty()) {
+        throw new IllegalArgumentException(
+            "Invalid argument, cluster name is required");
+      }
+
+      if (null == cluster) {
+        try {
+          cluster = getManagementController().getClusters().getCluster(
+              clusterName);
+        } catch (AmbariException e) {
+          throw new NoSuchResourceException(
+              "Parent Cluster resource doesn't exist", e);
+        }
+      }
+
+      // if asking for a single ID, get that historical entry and continue
+      // the for-loop
+      String id = (String) propertyMap.get(ALERT_HISTORY_ID);
+      if (null != id) {
+        AlertHistoryEntity entity = s_dao.findById(Long.parseLong(id));
+        if (null != entity) {
+          results.add(toResource(clusterName, entity, requestPropertyIds));
+          continue;
+        }
+      }
+
+      AlertHistoryRequest historyRequest = new AlertHistoryRequest();
+      historyRequest.Predicate = predicate;
+
+      List<AlertHistoryEntity> entities = s_dao.findAll(historyRequest);
+      for (AlertHistoryEntity entity : entities) {
+        results.add(toResource(cluster.getClusterName(), entity,
+            requestPropertyIds));
+      }
+    }
+
+    return results;
+  }
+
+  /**
+   * Converts the {@link AlertHistoryEntity} to a {@link Resource}.
+   *
+   * @param clusterName
+   *          the name of the cluster (not {@code null}).
+   * @param entity
+   *          the entity to convert (not {@code null}).
+   * @param requestedIds
+   *          the properties requested (not {@code null}).
+   * @return
+   */
+  private Resource toResource(String clusterName, AlertHistoryEntity entity,
+      Set<String> requestedIds) {
+    AlertDefinitionEntity definition = entity.getAlertDefinition();
+
+    Resource resource = new ResourceImpl(Resource.Type.AlertHistory);
+    resource.setProperty(ALERT_HISTORY_ID, entity.getAlertId());
+
+    setResourceProperty(resource, ALERT_HISTORY_CLUSTER_NAME, clusterName, requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_DEFINITION_ID, definition.getDefinitionId(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_DEFINITION_NAME, definition.getDefinitionName(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_SERVICE_NAME, entity.getServiceName(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_COMPONENT_NAME, entity.getComponentName(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_HOSTNAME, entity.getHostName(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_LABEL, entity.getAlertLabel(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_STATE, entity.getAlertState(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_TEXT, entity.getAlertText(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_TIMESTAMP, entity.getAlertTimestamp(), requestedIds);
+    setResourceProperty(resource, ALERT_HISTORY_INSTANCE, entity.getAlertInstance(), requestedIds);
+
+    return resource;
+  }
+}

+ 26 - 11
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProvider.java

@@ -28,14 +28,12 @@ import java.util.Map.Entry;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
@@ -55,7 +53,7 @@ import com.google.inject.Injector;
  * {@link AlertTargetEntity}.
  */
 public class AlertTargetResourceProvider extends
-    AbstractControllerResourceProvider {
+ AbstractResourceProvider {
 
   protected static final String ALERT_TARGET = "AlertTarget";
   protected static final String ALERT_TARGET_ID = "AlertTarget/id";
@@ -68,6 +66,29 @@ public class AlertTargetResourceProvider extends
   private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
       Arrays.asList(ALERT_TARGET_ID, ALERT_TARGET_NAME));
 
+  /**
+   * The property ids for an alert target resource.
+   */
+  private static final Set<String> PROPERTY_IDS = new HashSet<String>();
+
+  /**
+   * The key property ids for an alert target resource.
+   */
+  private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>();
+
+  static {
+    // properties
+    PROPERTY_IDS.add(ALERT_TARGET_ID);
+    PROPERTY_IDS.add(ALERT_TARGET_NAME);
+    PROPERTY_IDS.add(ALERT_TARGET_DESCRIPTION);
+    PROPERTY_IDS.add(ALERT_TARGET_NOTIFICATION_TYPE);
+    PROPERTY_IDS.add(ALERT_TARGET_PROPERTIES);
+    PROPERTY_IDS.add(ALERT_TARGET_GROUPS);
+
+    // keys
+    KEY_PROPERTY_IDS.put(Resource.Type.AlertTarget, ALERT_TARGET_ID);
+  }
+
   /**
    * Target DAO
    */
@@ -93,15 +114,9 @@ public class AlertTargetResourceProvider extends
 
   /**
    * Constructor.
-   *
-   * @param propertyIds
-   * @param keyPropertyIds
-   * @param managementController
    */
-  AlertTargetResourceProvider(Set<String> propertyIds,
-      Map<Type, String> keyPropertyIds,
-      AmbariManagementController managementController) {
-    super(propertyIds, keyPropertyIds, managementController);
+  AlertTargetResourceProvider() {
+    super(PROPERTY_IDS, KEY_PROPERTY_IDS);
   }
 
   @Override

+ 11 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java

@@ -21,13 +21,14 @@ package org.apache.ambari.server.controller.internal;
 import java.util.Map;
 import java.util.Set;
 
-import com.google.inject.Inject;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
+import com.google.inject.Inject;
+
 /**
  * The default provider module implementation.
  */
@@ -83,6 +84,15 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new LdapSyncEventResourceProvider(managementController);
       case UserPrivilege:
         return new UserPrivilegeResourceProvider();
+      case AlertDefinition:
+        return new AlertDefinitionResourceProvider(managementController);
+      case AlertHistory:
+        return new AlertHistoryResourceProvider(managementController);
+      case AlertTarget:
+        return new AlertTargetResourceProvider();
+      case AlertGroup:
+        return new AlertGroupResourceProvider(managementController);
+
       default:
         return AbstractControllerResourceProvider.getResourceProvider(type, propertyIds,
             keyPropertyIds, managementController);

+ 2 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java

@@ -116,6 +116,7 @@ public interface Resource {
     Permission,
     Alert,
     AlertDefinition,
+    AlertHistory,
     AlertGroup,
     AlertTarget,
     AmbariPrivilege,
@@ -202,6 +203,7 @@ public interface Resource {
     public static final Type Permission = InternalType.Permission.getType();
     public static final Type Alert = InternalType.Alert.getType();
     public static final Type AlertDefinition = InternalType.AlertDefinition.getType();
+    public static final Type AlertHistory = InternalType.AlertHistory.getType();
     public static final Type AlertGroup = InternalType.AlertGroup.getType();
     public static final Type AlertTarget = InternalType.AlertTarget.getType();
     public static final Type AmbariPrivilege = InternalType.AmbariPrivilege.getType();

+ 67 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertsDAO.java

@@ -24,10 +24,17 @@ import java.util.List;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.SingularAttribute;
 
+import org.apache.ambari.server.api.query.JpaPredicateVisitor;
+import org.apache.ambari.server.controller.AlertHistoryRequest;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.AlertCurrentEntity;
 import org.apache.ambari.server.orm.entities.AlertHistoryEntity;
+import org.apache.ambari.server.orm.entities.AlertHistoryEntity_;
 import org.apache.ambari.server.state.AlertState;
 import org.apache.ambari.server.state.alert.Scope;
 import org.eclipse.persistence.config.HintValues;
@@ -184,6 +191,33 @@ public class AlertsDAO {
     return daoUtils.selectList(query);
   }
 
+  /**
+   * Finds all {@link AlertHistoryEntity} that match the provided
+   * {@link AlertHistoryRequest}. This method will make JPA do the heavy lifting
+   * of providing a slice of the result set.
+   *
+   * @param request
+   * @return
+   */
+  @Transactional
+  public List<AlertHistoryEntity> findAll(AlertHistoryRequest request) {
+    EntityManager entityManager = entityManagerProvider.get();
+
+    // convert the Ambari predicate into a JPA predicate
+    HistoryPredicateVisitor visitor = new HistoryPredicateVisitor();
+    PredicateHelper.visit(request.Predicate, visitor);
+
+    CriteriaQuery<AlertHistoryEntity> query = visitor.getCriteriaQuery();
+    javax.persistence.criteria.Predicate jpaPredicate = visitor.getJpaPredicate();
+
+    if (null != jpaPredicate) {
+      query.where(jpaPredicate);
+    }
+
+    TypedQuery<AlertHistoryEntity> typedQuery = entityManager.createQuery(query);
+    return daoUtils.selectList(typedQuery);
+  }
+
   /**
    * Gets the current alerts.
    *
@@ -537,4 +571,37 @@ public class AlertsDAO {
     query.setHint(QueryHints.REFRESH, HintValues.TRUE);
     return query;
   }
+
+  /**
+   * The {@link HistoryPredicateVisitor} is used to convert an Ambari
+   * {@link Predicate} into a JPA {@link javax.persistence.criteria.Predicate}.
+   */
+  private final class HistoryPredicateVisitor extends
+      JpaPredicateVisitor<AlertHistoryEntity> {
+
+    /**
+     * Constructor.
+     *
+     */
+    public HistoryPredicateVisitor() {
+      super(entityManagerProvider.get(), AlertHistoryEntity.class);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<AlertHistoryEntity> getEntityClass() {
+      return AlertHistoryEntity.class;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<? extends SingularAttribute<?, ?>> getPredicateMapping(
+        String propertyId) {
+      return AlertHistoryEntity_.getPredicateMapping().get(propertyId);
+    }
+  }
 }

+ 50 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity_.java

@@ -0,0 +1,50 @@
+/*
+ * 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.orm.entities;
+
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.SetAttribute;
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.StaticMetamodel;
+
+import org.apache.ambari.server.state.alert.Scope;
+import org.apache.ambari.server.state.alert.SourceType;
+
+
+/**
+ * The {@link AlertDefinitionEntity_} is a strongly typed metamodel for creating
+ * {@link CriteriaQuery} for {@link AlertDefinitionEntity}.
+ */
+@StaticMetamodel(AlertDefinitionEntity.class)
+public class AlertDefinitionEntity_ {
+  public static volatile SingularAttribute<AlertDefinitionEntity, Long> definitionId;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> source;
+  public static volatile SingularAttribute<AlertDefinitionEntity, Long> clusterId;
+  public static volatile SingularAttribute<AlertDefinitionEntity, ClusterEntity> clusterEntity;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> componentName;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> definitionName;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> label;
+  public static volatile SingularAttribute<AlertDefinitionEntity, Scope> scope;
+  public static volatile SingularAttribute<AlertDefinitionEntity, Integer> enabled;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> hash;
+  public static volatile SingularAttribute<AlertDefinitionEntity, Integer> scheduleInterval;
+  public static volatile SingularAttribute<AlertDefinitionEntity, String> serviceName;
+  public static volatile SingularAttribute<AlertDefinitionEntity, SourceType> sourceType;
+  public static volatile SetAttribute<AlertDefinitionEntity, AlertGroupEntity> alertGroups;
+}

+ 94 - 0
ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertHistoryEntity_.java

@@ -0,0 +1,94 @@
+/*
+ * 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.orm.entities;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.StaticMetamodel;
+
+import org.apache.ambari.server.controller.internal.AlertHistoryResourceProvider;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.state.AlertState;
+
+
+/**
+ * The {@link AlertHistoryEntity_} is a strongly typed metamodel for creating
+ * {@link CriteriaQuery} for {@link AlertHistoryEntity}.
+ */
+@StaticMetamodel(AlertHistoryEntity.class)
+public class AlertHistoryEntity_ {
+  public static volatile SingularAttribute<AlertHistoryEntity, Long> alertId;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> alertInstance;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> alertLabel;
+  public static volatile SingularAttribute<AlertHistoryEntity, AlertState> alertState;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> alertText;
+  public static volatile SingularAttribute<AlertHistoryEntity, Long> alertTimestamp;
+  public static volatile SingularAttribute<AlertHistoryEntity, Long> clusterId;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> componentName;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> hostName;
+  public static volatile SingularAttribute<AlertHistoryEntity, String> serviceName;
+  public static volatile SingularAttribute<AlertHistoryEntity, AlertDefinitionEntity> alertDefinition;
+
+  /**
+   * Gets a mapping of between a resource provider property, like
+   * {@link AlertHistoryResourceProvider#ALERT_HISTORY_SERVICE_NAME} to a
+   * metamodel {@link SingularAttribute}.
+   * <p/>
+   * This is used when converting an Ambari {@link Predicate} into a JPA
+   * {@link javax.persistence.criteria.Predicate} and we need a type-safe
+   * conversion between "category/property" and JPA field names.
+   * <p/>
+   * Multiple {@link SingularAttribute} instances can be chained together in
+   * order to provide an {@code entity.subEntity.field} reference.
+   *
+   * @return
+   */
+  @SuppressWarnings("unchecked")
+  public static Map<String, List<? extends SingularAttribute<?, ?>>> getPredicateMapping() {
+    Map<String, List<? extends SingularAttribute<?, ?>>> mapping = new HashMap<String, List<? extends SingularAttribute<?, ?>>>();
+
+    mapping.put(AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME,
+        Collections.singletonList(serviceName));
+
+    mapping.put(
+        AlertHistoryResourceProvider.ALERT_HISTORY_COMPONENT_NAME,
+        Collections.singletonList(componentName));
+
+    mapping.put(AlertHistoryResourceProvider.ALERT_HISTORY_STATE,
+        Collections.singletonList(alertState));
+
+    mapping.put(AlertHistoryResourceProvider.ALERT_HISTORY_TIMESTAMP,
+        Collections.singletonList(alertTimestamp));
+
+    mapping.put(AlertHistoryResourceProvider.ALERT_HISTORY_HOSTNAME,
+        Collections.singletonList(hostName));
+
+    // AlertHistory.alertDefinition.definitionName = foo
+    mapping.put(AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME,
+        Arrays.asList(alertDefinition, AlertDefinitionEntity_.definitionName));
+
+    return mapping;
+  }
+}

+ 0 - 11
ambari-server/src/main/resources/key_properties.json

@@ -151,17 +151,6 @@
     "Host": "Alert/host_name",
     "Alert": "Alert/id"
   },
-  "AlertDefinition": {
-    "Cluster": "AlertDefinition/cluster_name",
-    "AlertDefinition": "AlertDefinition/id"
-  },
-  "AlertTarget": {
-    "AlertTarget": "AlertTarget/id"
-  },
-  "AlertGroup": {
-    "Cluster": "AlertGroup/cluster_name",
-    "AlertGroup": "AlertGroup/id"
-  },  
   "ClientConfig": {
     "Cluster": "ServiceComponentInfo/cluster_name",
     "Service": "ServiceComponentInfo/service_name",

+ 0 - 29
ambari-server/src/main/resources/properties.json

@@ -437,35 +437,6 @@
       "Alert/service_name",
       "Alert/scope"
     ],
-    "AlertDefinition": [
-      "AlertDefinition/cluster_name",
-      "AlertDefinition/service_name",
-      "AlertDefinition/component_name",
-      "AlertDefinition/id",
-      "AlertDefinition/name",
-      "AlertDefinition/label",
-      "AlertDefinition/interval",
-      "AlertDefinition/enabled",
-      "AlertDefinition/scope",
-      "AlertDefinition/source",
-      "AlertDefinition/run_now"
-    ],
-    "AlertGroup": [
-      "AlertGroup/id",
-      "AlertGroup/name",
-      "AlertGroup/cluster_name",
-      "AlertGroup/default",
-      "AlertGroup/definitions",
-      "AlertGroup/targets"
-    ],
-    "AlertTarget": [
-      "AlertTarget/id",
-      "AlertTarget/name",
-      "AlertTarget/description",      
-      "AlertTarget/notification_type",
-      "AlertTarget/properties",
-      "AlertTarget/groups"
-    ],
     "ClientConfig":[
         "ServiceComponentInfo/service_name",
         "ServiceComponentInfo/component_name",

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

@@ -451,10 +451,7 @@ public class AlertDefinitionResourceProviderTest {
    * @return
    */
   private AlertDefinitionResourceProvider createProvider(AmbariManagementController amc) {
-    return new AlertDefinitionResourceProvider(
-        PropertyHelper.getPropertyIds(Resource.Type.AlertDefinition),
-        PropertyHelper.getKeyPropertyIds(Resource.Type.AlertDefinition),
-        amc);
+    return new AlertDefinitionResourceProvider(amc);
   }
 
   /**

+ 1 - 3
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertGroupResourceProviderTest.java

@@ -528,9 +528,7 @@ public class AlertGroupResourceProviderTest {
   private AlertGroupResourceProvider createProvider(
       AmbariManagementController amc) {
 
-    return new AlertGroupResourceProvider(
-        PropertyHelper.getPropertyIds(Resource.Type.AlertGroup),
-        PropertyHelper.getKeyPropertyIds(Resource.Type.AlertGroup), amc);
+    return new AlertGroupResourceProvider(amc);
   }
 
   /**

+ 228 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertHistoryResourceProviderTest.java

@@ -0,0 +1,228 @@
+/**
+ * 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.controller.internal;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createStrictMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.AlertHistoryRequest;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertsDAO;
+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.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ * {@link AlertHistoryResourceProvider} tests.
+ */
+public class AlertHistoryResourceProviderTest {
+
+  private AlertsDAO m_dao = null;
+  private Injector m_injector;
+
+  @Before
+  public void before() {
+    m_dao = createStrictMock(AlertsDAO.class);
+
+    m_injector = Guice.createInjector(Modules.override(
+        new InMemoryDefaultTestModule()).with(new MockModule()));
+
+    AlertHistoryResourceProvider.init(m_injector);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetResourcesNoPredicate() throws Exception {
+    AlertHistoryResourceProvider provider = createProvider(null);
+
+    Request request = PropertyHelper.getReadRequest(
+        "AlertHistory/cluster_name", "AlertHistory/id");
+
+    Set<Resource> results = provider.getResources(request, null);
+    assertEquals(0, results.size());
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetResourcesClusterPredicate() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_ID,
+        AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_COMPONENT_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_HOSTNAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_STATE);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Clusters clusters = createMock(Clusters.class);
+    Cluster cluster = createMock(Cluster.class);
+    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+    expect(cluster.getClusterName()).andReturn("c1").atLeastOnce();
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").toPredicate();
+
+    expect(m_dao.findAll(EasyMock.anyObject(AlertHistoryRequest.class))).andReturn(
+        getMockEntities());
+
+    replay(amc, clusters, cluster, m_dao);
+
+    AlertHistoryResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+
+    Assert.assertEquals(
+        "namenode_definition",
+        r.getPropertyValue(AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME));
+
+    Assert.assertEquals(AlertState.WARNING,
+        r.getPropertyValue(AlertHistoryResourceProvider.ALERT_HISTORY_STATE));
+
+    verify(amc, clusters, cluster, m_dao);
+  }
+
+  /**
+   * @throws Exception
+   */
+  @Test
+  public void testGetSingleResource() throws Exception {
+    Request request = PropertyHelper.getReadRequest(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_ID,
+        AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_COMPONENT_NAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_HOSTNAME,
+        AlertHistoryResourceProvider.ALERT_HISTORY_STATE);
+
+    AmbariManagementController amc = createMock(AmbariManagementController.class);
+    Clusters clusters = createMock(Clusters.class);
+    Cluster cluster = createMock(Cluster.class);
+    expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
+    expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
+    expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+
+    Predicate predicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_ID).equals("1").toPredicate();
+
+    expect(m_dao.findById(1L)).andReturn(getMockEntities().get(0));
+
+    replay(amc, clusters, cluster, m_dao);
+
+    AlertHistoryResourceProvider provider = createProvider(amc);
+    Set<Resource> results = provider.getResources(request, predicate);
+
+    assertEquals(1, results.size());
+
+    Resource r = results.iterator().next();
+
+    Assert.assertEquals(
+        "namenode_definition",
+        r.getPropertyValue(AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME));
+
+    Assert.assertEquals(AlertState.WARNING,
+        r.getPropertyValue(AlertHistoryResourceProvider.ALERT_HISTORY_STATE));
+  }
+
+  /**
+   * @param amc
+   * @return
+   */
+  private AlertHistoryResourceProvider createProvider(
+      AmbariManagementController amc) {
+    return new AlertHistoryResourceProvider(amc);
+  }
+
+  /**
+   * @return
+   */
+  private List<AlertHistoryEntity> getMockEntities() throws Exception {
+    AlertDefinitionEntity definition = new AlertDefinitionEntity();
+    definition.setClusterId(1L);
+    definition.setComponentName("NAMENODE");
+    definition.setDefinitionName("namenode_definition");
+    definition.setEnabled(true);
+    definition.setServiceName("HDFS");
+
+    AlertHistoryEntity entity = new AlertHistoryEntity();
+    entity.setAlertId(1L);
+    entity.setAlertDefinition(definition);
+    entity.setClusterId(Long.valueOf(1L));
+    entity.setComponentName(null);
+    entity.setAlertText("Mock Label");
+    entity.setServiceName("HDFS");
+    entity.setAlertState(AlertState.WARNING);
+    entity.setAlertTimestamp(System.currentTimeMillis());
+    return Arrays.asList(entity);
+  }
+
+  /**
+  *
+  */
+  private class MockModule implements Module {
+    /**
+    *
+    */
+    @Override
+    public void configure(Binder binder) {
+      binder.bind(AlertsDAO.class).toInstance(m_dao);
+      binder.bind(Clusters.class).toInstance(
+          EasyMock.createNiceMock(Clusters.class));
+      binder.bind(Cluster.class).toInstance(
+          EasyMock.createNiceMock(Cluster.class));
+      binder.bind(ActionMetadata.class);
+    }
+  }
+}

+ 1 - 3
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertTargetResourceProviderTest.java

@@ -317,9 +317,7 @@ public class AlertTargetResourceProviderTest {
    */
   private AlertTargetResourceProvider createProvider(
       AmbariManagementController amc) {
-    return new AlertTargetResourceProvider(
-        PropertyHelper.getPropertyIds(Resource.Type.AlertTarget),
-        PropertyHelper.getKeyPropertyIds(Resource.Type.AlertTarget), amc);
+    return new AlertTargetResourceProvider();
   }
 
   /**

+ 168 - 0
ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertsDAOTest.java

@@ -37,6 +37,10 @@ import java.util.UUID;
 
 import junit.framework.Assert;
 
+import org.apache.ambari.server.controller.AlertHistoryRequest;
+import org.apache.ambari.server.controller.internal.AlertHistoryResourceProvider;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.events.listeners.AlertMaintenanceModeListener;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
@@ -763,7 +767,171 @@ public class AlertsDAOTest {
         assertEquals(MaintenanceState.OFF, current.getMaintenanceState());
       }
     }
+  }
+
+  /**
+   * Tests that the Ambari {@link Predicate} can be converted and submitted to
+   * JPA correctly to return a restricted result set.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testAlertHistoryPredicate() throws Exception {
+    Cluster cluster = initializeNewCluster();
+
+    // remove any definitions and start over
+    List<AlertDefinitionEntity> definitions = m_definitionDao.findAll();
+    for (AlertDefinitionEntity definition : definitions) {
+      m_definitionDao.remove(definition);
+    }
+
+    // create some definitions
+    AlertDefinitionEntity namenode = new AlertDefinitionEntity();
+    namenode.setDefinitionName("NAMENODE");
+    namenode.setServiceName("HDFS");
+    namenode.setComponentName("NAMENODE");
+    namenode.setClusterId(cluster.getClusterId());
+    namenode.setHash(UUID.randomUUID().toString());
+    namenode.setScheduleInterval(Integer.valueOf(60));
+    namenode.setScope(Scope.ANY);
+    namenode.setSource("{\"type\" : \"SCRIPT\"}");
+    namenode.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(namenode);
+
+    AlertDefinitionEntity datanode = new AlertDefinitionEntity();
+    datanode.setDefinitionName("DATANODE");
+    datanode.setServiceName("HDFS");
+    datanode.setComponentName("DATANODE");
+    datanode.setClusterId(cluster.getClusterId());
+    datanode.setHash(UUID.randomUUID().toString());
+    datanode.setScheduleInterval(Integer.valueOf(60));
+    datanode.setScope(Scope.HOST);
+    datanode.setSource("{\"type\" : \"SCRIPT\"}");
+    datanode.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(datanode);
+
+    AlertDefinitionEntity aggregate = new AlertDefinitionEntity();
+    aggregate.setDefinitionName("YARN_AGGREGATE");
+    aggregate.setServiceName("YARN");
+    aggregate.setComponentName(null);
+    aggregate.setClusterId(cluster.getClusterId());
+    aggregate.setHash(UUID.randomUUID().toString());
+    aggregate.setScheduleInterval(Integer.valueOf(60));
+    aggregate.setScope(Scope.SERVICE);
+    aggregate.setSource("{\"type\" : \"SCRIPT\"}");
+    aggregate.setSourceType(SourceType.SCRIPT);
+    m_definitionDao.create(aggregate);
+
+    // create some history
+    AlertHistoryEntity nnHistory = new AlertHistoryEntity();
+    nnHistory.setAlertState(AlertState.OK);
+    nnHistory.setServiceName(namenode.getServiceName());
+    nnHistory.setComponentName(namenode.getComponentName());
+    nnHistory.setClusterId(cluster.getClusterId());
+    nnHistory.setAlertDefinition(namenode);
+    nnHistory.setAlertLabel(namenode.getDefinitionName());
+    nnHistory.setAlertText(namenode.getDefinitionName());
+    nnHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    nnHistory.setHostName(HOSTNAME);
+    m_dao.create(nnHistory);
+
+    AlertHistoryEntity dnHistory = new AlertHistoryEntity();
+    dnHistory.setAlertState(AlertState.WARNING);
+    dnHistory.setServiceName(datanode.getServiceName());
+    dnHistory.setComponentName(datanode.getComponentName());
+    dnHistory.setClusterId(cluster.getClusterId());
+    dnHistory.setAlertDefinition(datanode);
+    dnHistory.setAlertLabel(datanode.getDefinitionName());
+    dnHistory.setAlertText(datanode.getDefinitionName());
+    dnHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    dnHistory.setHostName(HOSTNAME);
+    m_dao.create(dnHistory);
+
+    AlertHistoryEntity aggregateHistory = new AlertHistoryEntity();
+    aggregateHistory.setAlertState(AlertState.CRITICAL);
+    aggregateHistory.setServiceName(aggregate.getServiceName());
+    aggregateHistory.setComponentName(aggregate.getComponentName());
+    aggregateHistory.setClusterId(cluster.getClusterId());
+    aggregateHistory.setAlertDefinition(aggregate);
+    aggregateHistory.setAlertLabel(aggregate.getDefinitionName());
+    aggregateHistory.setAlertText(aggregate.getDefinitionName());
+    aggregateHistory.setAlertTimestamp(calendar.getTimeInMillis());
+    m_dao.create(aggregateHistory);
+
+    List<AlertHistoryEntity> histories = m_dao.findAll();
+    assertEquals(3, histories.size());
+
+    Predicate clusterPredicate = null;
+    Predicate hdfsPredicate = null;
+    Predicate yarnPredicate = null;
+    Predicate clusterAndHdfsPredicate = null;
+    Predicate clusterAndHdfsAndCriticalPredicate = null;
+    Predicate hdfsAndCriticalOrWarningPredicate = null;
+    Predicate alertNamePredicate = null;
+
+    clusterPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").toPredicate();
+
+    AlertHistoryRequest request = new AlertHistoryRequest();
+
+    request.Predicate = clusterPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(3, histories.size());
+
+    hdfsPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("HDFS").toPredicate();
+
+    yarnPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("YARN").toPredicate();
+
+    clusterAndHdfsPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("HDFS").toPredicate();
+
+    clusterAndHdfsPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("HDFS").toPredicate();
+
+    clusterAndHdfsAndCriticalPredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_CLUSTER_NAME).equals("c1").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("HDFS").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_STATE).equals(
+        AlertState.CRITICAL.name()).toPredicate();
+
+    hdfsAndCriticalOrWarningPredicate = new PredicateBuilder().begin().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_SERVICE_NAME).equals("HDFS").and().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_STATE).equals(
+        AlertState.CRITICAL.name()).end().or().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_STATE).equals(
+        AlertState.WARNING.name()).toPredicate();
+
+    alertNamePredicate = new PredicateBuilder().property(
+        AlertHistoryResourceProvider.ALERT_HISTORY_DEFINITION_NAME).equals(
+        "NAMENODE").toPredicate();
+
+    request.Predicate = hdfsPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(2, histories.size());
+
+    request.Predicate = yarnPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(1, histories.size());
+
+    request.Predicate = clusterAndHdfsPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(2, histories.size());
+
+    request.Predicate = clusterAndHdfsAndCriticalPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(0, histories.size());
+
+    request.Predicate = hdfsAndCriticalOrWarningPredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(1, histories.size());
 
+    request.Predicate = alertNamePredicate;
+    histories = m_dao.findAll(request);
+    assertEquals(1, histories.size());
   }
 
   private Cluster initializeNewCluster() throws Exception {