/*
* 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.apache.ambari.server.orm.RequiresSession;
import org.apache.ambari.server.orm.entities.ServiceConfigEntity;
import org.apache.ambari.server.orm.entities.StackEntity;
import org.apache.ambari.server.state.StackId;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
@Singleton
public class ServiceConfigDAO {
@Inject
private Provider<EntityManager> entityManagerProvider;
@Inject
private StackDAO stackDAO;
@Inject
private DaoUtils daoUtils;
@RequiresSession
public ServiceConfigEntity find(Long serviceConfigId) {
return entityManagerProvider.get().find(ServiceConfigEntity.class, serviceConfigId);
}
@RequiresSession
public ServiceConfigEntity findByServiceAndVersion(String serviceName, Long version) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().
createQuery("SELECT scv FROM ServiceConfigEntity scv " +
"WHERE scv.serviceName=?1 AND scv.version=?2", ServiceConfigEntity.class);
return daoUtils.selectOne(query, serviceName, version);
}
@RequiresSession
public List<ServiceConfigEntity> findByService(Long clusterId, String serviceName) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().
createQuery("SELECT scv FROM ServiceConfigEntity scv " +
"WHERE scv.clusterId=?1 AND scv.serviceName=?2", ServiceConfigEntity.class);
return daoUtils.selectList(query, clusterId, serviceName);
}
@RequiresSession
public List<ServiceConfigEntity> getLastServiceConfigVersionsForGroups(Collection<Long> configGroupIds) {
if (configGroupIds == null || configGroupIds.isEmpty()) {
return Collections.emptyList();
}
CriteriaBuilder cb = entityManagerProvider.get().getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<ServiceConfigEntity> groupVersion = cq.from(ServiceConfigEntity.class);
cq.multiselect(groupVersion.get("groupId").alias("groupId"), cb.max(groupVersion.<Long>get("version")).alias("lastVersion"));
cq.where(groupVersion.get("groupId").in(configGroupIds));
cq.groupBy(groupVersion.get("groupId"));
List<Tuple> tuples = daoUtils.selectList(entityManagerProvider.get().createQuery(cq));
List<ServiceConfigEntity> result = new ArrayList<>();
//subquery look to be very poor, no bulk select then, cache should help here as result size is naturally limited
for (Tuple tuple : tuples) {
CriteriaQuery<ServiceConfigEntity> sce = cb.createQuery(ServiceConfigEntity.class);
Root<ServiceConfigEntity> sceRoot = sce.from(ServiceConfigEntity.class);
sce.where(cb.and(cb.equal(sceRoot.get("groupId"), tuple.get("groupId")),
cb.equal(sceRoot.get("version"), tuple.get("lastVersion"))));
sce.select(sceRoot);
result.add(daoUtils.selectSingle(entityManagerProvider.get().createQuery(sce)));
}
return result;
}
@RequiresSession
public List<Long> getServiceConfigVersionsByConfig(Long clusterId, String configType, Long configVersion) {
TypedQuery<Long> query = entityManagerProvider.get().createQuery("SELECT scv.version " +
"FROM ServiceConfigEntity scv JOIN scv.clusterConfigEntities cc " +
"WHERE cc.clusterId=?1 AND cc.type = ?2 AND cc.version = ?3", Long.class);
return daoUtils.selectList(query, clusterId, configType, configVersion);
}
@RequiresSession
public List<ServiceConfigEntity> getLastServiceConfigs(Long clusterId) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findLatestServiceConfigsByCluster",
ServiceConfigEntity.class);
query.setParameter("clusterId", clusterId);
return daoUtils.selectList(query);
}
/**
* Gets the latest service config versions of all config groups for a service
* @param clusterId
* the cluster (not {@code null}).
* @param serviceName
* Name of the service whose latest service config versions needs to be retrieved .
* @return all service configurations for the cluster and service.
*/
@RequiresSession
public List<ServiceConfigEntity> getLastServiceConfigsForService(Long clusterId, String serviceName) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findLatestServiceConfigsByService",
ServiceConfigEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("serviceName", serviceName);
return daoUtils.selectList(query);
}
/**
* Get all service configurations for the specified cluster and stack. This
* will return different versions of the same configuration (HDFS v1 and v2)
* if they exist.
*
* @param clusterId
* the cluster (not {@code null}).
* @param stackId
* the stack (not {@code null}).
* @return all service configurations for the cluster and stack.
*/
@RequiresSession
public List<ServiceConfigEntity> getAllServiceConfigsForClusterAndStack(Long clusterId,
StackId stackId) {
StackEntity stackEntity = stackDAO.find(stackId.getStackName(),
stackId.getStackVersion());
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findAllServiceConfigsByStack",
ServiceConfigEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("stack", stackEntity);
return daoUtils.selectList(query);
}
/**
* Gets the latest service configurations for the specified cluster and stack.
*
* @param clusterId
* the cluster (not {@code null}).
* @param stackId
* the stack (not {@code null}).
* @return the latest service configurations for the cluster and stack.
*/
@RequiresSession
public List<ServiceConfigEntity> getLatestServiceConfigs(Long clusterId,
StackId stackId) {
StackEntity stackEntity = stackDAO.find(stackId.getStackName(),
stackId.getStackVersion());
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findLatestServiceConfigsByStack",
ServiceConfigEntity.class);
query.setParameter("clusterId", clusterId);
query.setParameter("stack", stackEntity);
return daoUtils.selectList(query);
}
@RequiresSession
public ServiceConfigEntity getLastServiceConfig(Long clusterId, String serviceName) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().
createQuery("SELECT scv FROM ServiceConfigEntity scv " +
"WHERE scv.clusterId = ?1 AND scv.serviceName = ?2 " +
"ORDER BY scv.createTimestamp DESC",
ServiceConfigEntity.class);
return daoUtils.selectOne(query, clusterId, serviceName);
}
@RequiresSession
public ServiceConfigEntity findMaxVersion(Long clusterId, String serviceName) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createQuery("SELECT scv FROM ServiceConfigEntity scv " +
"WHERE scv.clusterId=?1 AND scv.serviceName=?2 AND scv.version = (" +
"SELECT max(scv2.version) FROM ServiceConfigEntity scv2 " +
"WHERE scv2.clusterId=?1 AND scv2.serviceName=?2)", ServiceConfigEntity.class);
return daoUtils.selectSingle(query, clusterId, serviceName);
}
/**
* Get all service configs for the given cluster.
* @param clusterId Cluster Id
* @return Collection of service configs in the given cluster.
*/
@RequiresSession
public List<ServiceConfigEntity> getServiceConfigs(Long clusterId) {
TypedQuery<ServiceConfigEntity> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findAll", ServiceConfigEntity.class);
query.setParameter("clusterId", clusterId);
return daoUtils.selectList(query);
}
/**
* Get all service configs
* @return Collection of all service configs.
*/
@RequiresSession
public List<ServiceConfigEntity> findAll() {
return daoUtils.selectAll(entityManagerProvider.get(), ServiceConfigEntity.class);
}
/**
* Gets the next version that will be created when persisting a new
* {@link ServiceConfigEntity}.
*
* @param clusterId
* the cluster that the service is a part of.
* @param serviceName
* the name of the service (not {@code null}).
* @return the maximum version value + 1
*/
@RequiresSession
public Long findNextServiceConfigVersion(long clusterId, String serviceName) {
TypedQuery<Number> query = entityManagerProvider.get().createNamedQuery(
"ServiceConfigEntity.findNextServiceConfigVersion", Number.class);
query.setParameter("clusterId", clusterId);
query.setParameter("serviceName", serviceName);
return daoUtils.selectSingle(query).longValue();
}
@Transactional
public void removeHostFromServiceConfigs(final Long hostId) {
List<ServiceConfigEntity> allServiceConfigs = this.findAll();
for (ServiceConfigEntity serviceConfigEntity : allServiceConfigs) {
List<Long> hostIds = serviceConfigEntity.getHostIds();
if (hostIds != null && hostIds.contains(hostId)) {
// Remove the hostId
CollectionUtils.filter(hostIds, new Predicate() {
@Override
public boolean evaluate(Object arg0) {
return !((Long) arg0).equals(hostId);
}
});
serviceConfigEntity.setHostIds(hostIds);
}
}
}
@Transactional
public void create(ServiceConfigEntity serviceConfigEntity) {
entityManagerProvider.get().persist(serviceConfigEntity);
}
@Transactional
public ServiceConfigEntity merge(ServiceConfigEntity serviceConfigEntity) {
return entityManagerProvider.get().merge(serviceConfigEntity);
}
@Transactional
public void remove(ServiceConfigEntity serviceConfigEntity) {
entityManagerProvider.get().remove(merge(serviceConfigEntity));
}
}