blob: 7f7fd4526bd72e3c76758c76dd3c189f1f7fa442 [file] [log] [blame]
/*
* 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.dao;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.agent.stomp.dto.AlertGroupUpdate;
import org.apache.ambari.server.controller.RootComponent;
import org.apache.ambari.server.controller.RootService;
import org.apache.ambari.server.controller.internal.AlertDefinitionResourceProvider;
import org.apache.ambari.server.events.AlertDefinitionChangedEvent;
import org.apache.ambari.server.events.AlertDefinitionDeleteEvent;
import org.apache.ambari.server.events.AlertDefinitionRegistrationEvent;
import org.apache.ambari.server.events.AlertGroupsUpdateEvent;
import org.apache.ambari.server.events.UpdateEventType;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.events.publishers.STOMPUpdatePublisher;
import org.apache.ambari.server.orm.RequiresSession;
import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
import org.apache.ambari.server.orm.entities.AlertGroupEntity;
import org.apache.ambari.server.state.alert.AlertDefinition;
import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
import org.apache.ambari.server.state.alert.Scope;
import org.apache.ambari.server.state.alert.SourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
/**
* The {@link AlertDefinitionDAO} class is used to manage the persistence and
* retrieval of {@link AlertDefinitionEntity} instances.
*/
@Singleton
public class AlertDefinitionDAO {
/**
* Logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(AlertDefinitionDAO.class);
/**
* JPA entity manager
*/
@Inject
private Provider<EntityManager> entityManagerProvider;
/**
* DAO utilities for dealing mostly with {@link TypedQuery} results.
*/
@Inject
private DaoUtils daoUtils;
/**
* Alert history DAO.
*/
@Inject
private AlertsDAO alertsDao;
/**
* Alert dispatch DAO.
*/
@Inject
private AlertDispatchDAO dispatchDao;
/**
* Publishes the following events:
* <ul>
* <li>{@link AlertDefinitionRegistrationEvent} when new alerts are merged
* from the stack or created from the {@link AlertDefinitionResourceProvider}</li>
* <li>{@link AlertDefinitionChangedEvent} when alerts are updated.</li>
* <li>{@link AlertDefinitionDeleteEvent} when alerts are removed</li>
* </ul>
*/
@Inject
private AmbariEventPublisher eventPublisher;
/**
* A factory that assists in the creation of {@link AlertDefinition} and
* {@link AlertDefinitionEntity}.
*/
@Inject
private AlertDefinitionFactory alertDefinitionFactory;
@Inject
private STOMPUpdatePublisher STOMPUpdatePublisher;
/**
* Gets an alert definition with the specified ID.
*
* @param definitionId
* 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);
}
/**
* Gets an alert definition with the specified name. Alert definition names
* are unique within a cluster.
*
* @param clusterId
* the ID of the cluster.
* @param definitionName
* 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);
query.setParameter("clusterId", clusterId);
query.setParameter("definitionName", definitionName);
return daoUtils.selectSingle(query);
}
/**
* Gets all alert definitions stored in the database.
*
* @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);
return daoUtils.selectList(query);
}
/**
* Gets all alert definitions stored in the database.
*
* @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);
query.setParameter("clusterId", clusterId);
return daoUtils.selectList(query);
}
/**
* Gets all enabled alert definitions stored in the database for the specified
* cluster.
*
* @return all enabled alert definitions or empty list if none exist (never
* {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findAllEnabled(long clusterId) {
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findAllEnabledInCluster",
AlertDefinitionEntity.class);
query.setParameter("clusterId", clusterId);
return daoUtils.selectList(query);
}
/**
* Gets all of the alert definitions for the list of IDs given.
*
* @param definitionIds
* the IDs of the definitions to retrieve.
* @return the definition or an empty list (never {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findByIds(List<Long> definitionIds) {
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findByIds", AlertDefinitionEntity.class);
query.setParameter("definitionIds", definitionIds);
return daoUtils.selectList(query);
}
/**
* Gets all alert definitions for the given service in the specified cluster.
*
* @param clusterId
* the ID of the cluster.
* @param serviceName
* the name of the service.
*
* @return all alert definitions for the service or empty list if none exist
* (never {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findByService(long clusterId,
String serviceName) {
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findByService", AlertDefinitionEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("serviceName", serviceName);
return daoUtils.selectList(query);
}
/**
* Gets all alert definitions for the specified services that do not have a
* component and do not belong to AGGREGATE source type. These definitions are assumed to be run on the master hosts.
*
* @param clusterId
* the ID of the cluster.
* @param services
* the services to match on.
*
* @return all alert definitions for the services or empty list if none exist
* (never {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findByServiceMaster(long clusterId,
Set<String> services) {
if (null == services || services.size() == 0) {
return Collections.emptyList();
}
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findByServiceMaster",
AlertDefinitionEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("services", services);
query.setParameter("scope", Scope.SERVICE);
return daoUtils.selectList(query);
}
/**
* Gets all alert definitions that are not bound to a particular service. An
* example of this type of definition is a host capacity alert.
*
* @param clusterId
* the ID of the cluster.
* @param serviceName
* the name of the service (not {@code null}).
* @param componentName
* the name of the service component (not {@code null}).
* @return all alert definitions that are not bound to a service or an empty
* list (never {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findByServiceComponent(long clusterId,
String serviceName, String componentName) {
if (null == serviceName || null == componentName) {
return Collections.emptyList();
}
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findByServiceAndComponent",
AlertDefinitionEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("serviceName", serviceName);
query.setParameter("componentName", componentName);
return daoUtils.selectList(query);
}
/**
* Gets all alert definitions that are not bound to a particular service. An
* example of this type of definition is a host capacity alert.
*
* @param clusterId
* the ID of the cluster.
* @return all alert definitions that are not bound to a service or an empty
* list (never {@code null}).
*/
@RequiresSession
public List<AlertDefinitionEntity> findAgentScoped(long clusterId) {
TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
"AlertDefinitionEntity.findByServiceAndComponent",
AlertDefinitionEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("serviceName",
RootService.AMBARI.name());
query.setParameter("componentName",
RootComponent.AMBARI_AGENT.name());
return daoUtils.selectList(query);
}
/**
* @return all definitions with the given sourceType
*/
@RequiresSession
public List<AlertDefinitionEntity> findBySourceType(Long clusterId, SourceType sourceType) {
return daoUtils.selectList(
entityManagerProvider.get()
.createNamedQuery("AlertDefinitionEntity.findBySourceType", AlertDefinitionEntity.class)
.setParameter("clusterId", clusterId)
.setParameter("sourceType", sourceType));
}
/**
* Persists a new alert definition, also creating the associated
* {@link AlertGroupEntity} relationship for the definition's service default
* group. Fires an {@link AlertDefinitionRegistrationEvent}.
*
* @param alertDefinition
* the definition to persist (not {@code null}).
*/
@Transactional
public void create(AlertDefinitionEntity alertDefinition)
throws AmbariException {
EntityManager entityManager = entityManagerProvider.get();
entityManager.persist(alertDefinition);
AlertGroupEntity group = dispatchDao.findDefaultServiceGroup(alertDefinition.getClusterId(),
alertDefinition.getServiceName());
if (null == group) {
// create the default alert group for the new service; this MUST be done
// before adding definitions so that they are properly added to the
// default group
String serviceName = alertDefinition.getServiceName();
group = dispatchDao.createDefaultGroup(alertDefinition.getClusterId(), serviceName);
}
group.addAlertDefinition(alertDefinition);
AlertGroupsUpdateEvent alertGroupsUpdateEvent = new AlertGroupsUpdateEvent(Collections.singletonList(
new AlertGroupUpdate(group)),
UpdateEventType.UPDATE);
STOMPUpdatePublisher.publish(alertGroupsUpdateEvent);
dispatchDao.merge(group);
// publish the alert definition registration
AlertDefinition coerced = alertDefinitionFactory.coerce(alertDefinition);
if (null != coerced) {
AlertDefinitionRegistrationEvent event = new AlertDefinitionRegistrationEvent(
alertDefinition.getClusterId(), coerced);
eventPublisher.publish(event);
} else {
LOG.warn("Unable to broadcast alert registration event for {}",
alertDefinition.getDefinitionName());
}
entityManager.refresh(alertDefinition);
}
/**
* Refresh the state of the alert definition from the database.
*
* @param alertDefinition
* the definition to refresh (not {@code null}).
*/
@Transactional
public void refresh(AlertDefinitionEntity alertDefinition) {
entityManagerProvider.get().refresh(alertDefinition);
}
/**
* Merge the speicified alert definition with the existing definition in the
* database. Fires an {@link AlertDefinitionChangedEvent}.
*
* @param alertDefinition
* the definition to merge (not {@code null}).
* @return the updated definition with merged content (never {@code null}).
*/
@Transactional
public AlertDefinitionEntity merge(AlertDefinitionEntity alertDefinition) {
AlertDefinitionEntity entity = entityManagerProvider.get().merge(alertDefinition);
AlertDefinition definition = alertDefinitionFactory.coerce(entity);
AlertDefinitionChangedEvent event = new AlertDefinitionChangedEvent(
alertDefinition.getClusterId(), definition);
eventPublisher.publish(event);
return entity;
}
/**
* Creates or updates the specified entity. This method will check
* {@link AlertDefinitionEntity#getDefinitionId()} in order to determine
* whether the entity should be created or merged.
*
* @param alertDefinition
* the definition to create or update (not {@code null}).
*/
public void createOrUpdate(AlertDefinitionEntity alertDefinition)
throws AmbariException {
if (null == alertDefinition.getDefinitionId()) {
create(alertDefinition);
} else {
merge(alertDefinition);
}
}
/**
* Removes the specified alert definition and all related history and
* associations from the database. Fires an {@link AlertDefinitionDeleteEvent}
* .
*
* @param alertDefinition
* the definition to remove.
*/
@Transactional
public void remove(AlertDefinitionEntity alertDefinition) {
dispatchDao.removeNoticeByDefinitionId(alertDefinition.getDefinitionId());
alertsDao.removeByDefinitionId(alertDefinition.getDefinitionId());
EntityManager entityManager = entityManagerProvider.get();
alertDefinition = findById(alertDefinition.getDefinitionId());
if (null != alertDefinition) {
entityManager.remove(alertDefinition);
// publish the alert definition removal
AlertDefinition coerced = alertDefinitionFactory.coerce(alertDefinition);
if (null != coerced) {
AlertDefinitionDeleteEvent event = new AlertDefinitionDeleteEvent(
alertDefinition.getClusterId(), coerced);
eventPublisher.publish(event);
} else {
LOG.warn("Unable to broadcast alert removal event for {}",
alertDefinition.getDefinitionName());
}
}
}
/**
* Removes all {@link AlertDefinitionEntity} that are associated with the
* specified cluster ID.
*
* @param clusterId
* the cluster ID.
*/
@Transactional
public void removeAll(long clusterId) {
List<AlertDefinitionEntity> definitions = findAll(clusterId);
for (AlertDefinitionEntity definition : definitions) {
remove(definition);
}
}
}