package rocks.inspectit.server.dao.impl;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import rocks.inspectit.server.dao.DefaultDataDao;
import rocks.inspectit.server.processor.AbstractCmrDataProcessor;
import rocks.inspectit.shared.all.communication.DefaultData;
import rocks.inspectit.shared.all.communication.MethodSensorData;
import rocks.inspectit.shared.all.communication.data.HttpInfo;
import rocks.inspectit.shared.all.communication.data.HttpTimerData;
import rocks.inspectit.shared.all.communication.data.JmxSensorValueData;
import rocks.inspectit.shared.all.communication.data.SystemInformationData;
import rocks.inspectit.shared.all.spring.logger.Log;
/**
* The default implementation of the {@link DefaultDataDao} interface by using the Entity manager.
*
* @author Patrice Bouillet
* @author Eduard Tudenhoefner
* @author Ivan Senic
* @author Stefan Siegl
*/
@Repository
public class DefaultDataDaoImpl implements DefaultDataDao {
/** The logger of this class. */
@Log
Logger log;
/**
* List of processors.
*/
@Autowired
@Resource(name = "cmrDataProcessorList")
// resource must be specified, otherwise all processor all plugged here
private List<AbstractCmrDataProcessor> cmrDataProcessors;
/**
* Entity manager.
*/
@PersistenceContext
private EntityManager entityManager;
/**
* {@inheritDoc}
* <p>
* We must mark this as transactional cause it's running outside our services.
*/
@Override
@Transactional
public void saveAll(List<? extends DefaultData> defaultDataCollection) {
try {
for (AbstractCmrDataProcessor processor : cmrDataProcessors) {
processor.process(defaultDataCollection, entityManager);
}
} catch (Exception e) {
log.error("Error occurred trying to process the CMR data processors on the incoming data.", e);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<DefaultData> findByExampleWithLastInterval(DefaultData template, long timeInterval) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<DefaultData> criteria = builder.createQuery(DefaultData.class);
Root<? extends DefaultData> root = criteria.from(template.getClass());
criteria.select(root);
Predicate platformId = builder.equal(root.get("platformIdent"), template.getPlatformIdent());
Predicate sensorTypeId = builder.equal(root.get("sensorTypeIdent"), template.getSensorTypeIdent());
Predicate timestamp = builder.greaterThan(root.<Timestamp> get("timeStamp"), new Timestamp(System.currentTimeMillis() - timeInterval));
if (template instanceof MethodSensorData) {
MethodSensorData methodSensorData = (MethodSensorData) template;
Predicate methodId = builder.equal(root.get("methodIdent"), methodSensorData.getMethodIdent());
criteria.where(platformId, sensorTypeId, timestamp, methodId);
} else if (template instanceof JmxSensorValueData) {
JmxSensorValueData jmxSensorValueData = (JmxSensorValueData) template;
Predicate jmxSensorDefinitionDataId = builder.equal(root.get("jmxSensorDefinitionDataIdentId"), jmxSensorValueData.getJmxSensorDefinitionDataIdentId());
criteria.where(platformId, sensorTypeId, timestamp, jmxSensorDefinitionDataId);
} else {
criteria.where(platformId, sensorTypeId, timestamp);
}
return entityManager.createQuery(criteria).getResultList();
}
/**
* {@inheritDoc}
*/
@Override
public List<DefaultData> findByExampleSinceId(DefaultData template) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<DefaultData> criteria = builder.createQuery(DefaultData.class);
Root<? extends DefaultData> root = criteria.from(template.getClass());
criteria.select(root);
Predicate id = builder.greaterThan(root.<Long> get("id"), template.getId());
Predicate platformId = builder.equal(root.get("platformIdent"), template.getPlatformIdent());
Predicate sensorTypeId = builder.equal(root.get("sensorTypeIdent"), template.getSensorTypeIdent());
if (template instanceof MethodSensorData) {
MethodSensorData methodSensorData = (MethodSensorData) template;
Predicate methodId = builder.equal(root.get("methodIdent"), methodSensorData.getMethodIdent());
criteria.where(id, platformId, sensorTypeId, methodId);
} else if (template instanceof JmxSensorValueData) {
JmxSensorValueData jmxSensorValueData = (JmxSensorValueData) template;
Predicate jmxSensorDefinitionDataId = builder.equal(root.get("jmxSensorDefinitionDataIdentId"), jmxSensorValueData.getJmxSensorDefinitionDataIdentId());
criteria.where(id, platformId, sensorTypeId, jmxSensorDefinitionDataId);
} else {
criteria.where(id, platformId, sensorTypeId);
}
return entityManager.createQuery(criteria).getResultList();
}
/**
* {@inheritDoc}
*/
@Override
public List<DefaultData> findByExampleSinceIdIgnoreMethodId(DefaultData template) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<DefaultData> criteria = builder.createQuery(DefaultData.class);
Root<? extends DefaultData> root = criteria.from(template.getClass());
criteria.select(root);
Predicate id = builder.greaterThan(root.<Long> get("id"), template.getId());
Predicate platformId = builder.equal(root.get("platformIdent"), template.getPlatformIdent());
criteria.where(id, platformId);
return entityManager.createQuery(criteria).getResultList();
}
/**
* {@inheritDoc}
*/
@Override
public List<DefaultData> findByExampleFromToDate(DefaultData template, Date fromDate, Date toDate) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<DefaultData> criteria = builder.createQuery(DefaultData.class);
Root<? extends DefaultData> root = criteria.from(template.getClass());
criteria.select(root);
Predicate platformId = builder.equal(root.get("platformIdent"), template.getPlatformIdent());
Predicate sensorTypeId = builder.equal(root.get("sensorTypeIdent"), template.getSensorTypeIdent());
Predicate timestamp = builder.between(root.<Timestamp> get("timeStamp"), new Timestamp(fromDate.getTime()), new Timestamp(toDate.getTime()));
if (template instanceof MethodSensorData) {
MethodSensorData methodSensorData = (MethodSensorData) template;
Predicate methodId = builder.equal(root.get("methodIdent"), methodSensorData.getMethodIdent());
criteria.where(platformId, sensorTypeId, timestamp, methodId);
} else if (template instanceof JmxSensorValueData) {
JmxSensorValueData jmxSensorValueData = (JmxSensorValueData) template;
Predicate jmxSensorDefinitionDataId = builder.equal(root.get("jmxSensorDefinitionDataIdentId"), jmxSensorValueData.getJmxSensorDefinitionDataIdentId());
criteria.where(platformId, sensorTypeId, timestamp, jmxSensorDefinitionDataId);
} else {
criteria.where(platformId, sensorTypeId, timestamp);
}
return entityManager.createQuery(criteria).getResultList();
}
/**
* {@inheritDoc}
*/
@Override
public DefaultData findByExampleLastData(DefaultData template) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<DefaultData> criteria = builder.createQuery(DefaultData.class);
Root<? extends DefaultData> root = criteria.from(template.getClass());
criteria.select(root);
Predicate platformId = builder.equal(root.get("platformIdent"), template.getPlatformIdent());
if (template instanceof MethodSensorData) {
MethodSensorData methodSensorData = (MethodSensorData) template;
Predicate methodId = builder.equal(root.get("methodIdent"), methodSensorData.getMethodIdent());
criteria.where(platformId, methodId);
} else if (template instanceof JmxSensorValueData) {
JmxSensorValueData jmxSensorValueData = (JmxSensorValueData) template;
Predicate jmxSensorDefinitionDataId = builder.equal(root.get("jmxSensorDefinitionDataIdentId"), jmxSensorValueData.getJmxSensorDefinitionDataIdentId());
criteria.where(platformId, jmxSensorDefinitionDataId);
} else {
criteria.where(platformId);
}
criteria.orderBy(builder.desc(root.get("id")));
List<DefaultData> results = entityManager.createQuery(criteria).setMaxResults(1).getResultList();
if (CollectionUtils.isNotEmpty(results)) {
return results.get(0);
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public List<HttpTimerData> getChartingHttpTimerDataFromDateToDate(Collection<HttpTimerData> templates, Date fromDate, Date toDate, boolean retrieveByTag) {
if (CollectionUtils.isNotEmpty(templates)) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<HttpTimerData> criteria = builder.createQuery(HttpTimerData.class);
Root<? extends HttpTimerData> root = criteria.from(HttpTimerData.class);
Predicate platformId = builder.equal(root.get("platformIdent"), templates.iterator().next().getPlatformIdent());
Predicate timestamp = builder.between(root.<Timestamp> get("timeStamp"), new Timestamp(fromDate.getTime()), new Timestamp(toDate.getTime()));
Predicate condition = null;
if (!retrieveByTag) {
Set<String> uris = new HashSet<>();
for (HttpTimerData httpTimerData : templates) {
if (!HttpInfo.UNDEFINED.equals(httpTimerData.getHttpInfo().getUri())) {
uris.add(httpTimerData.getHttpInfo().getUri());
}
}
condition = root.join("httpInfo").get("uri").in(uris);
} else {
Set<String> tags = new HashSet<>();
for (HttpTimerData httpTimerData : templates) {
if (httpTimerData.getHttpInfo().hasInspectItTaggingHeader()) {
tags.add(httpTimerData.getHttpInfo().getInspectItTaggingHeaderValue());
}
}
condition = root.join("httpInfo").get("inspectItTaggingHeaderValue").in(tags);
}
criteria.where(platformId, timestamp, condition);
return entityManager.createQuery(criteria).getResultList();
} else {
return Collections.emptyList();
}
}
/**
* {@inheritDoc}
*/
@Override
public void deleteAll(Long platformId) {
// we need to delete each instance of the SystemInformationData, so that all VmArgumentData
// orphans are also deleted, cause it can not be done with H2
Query query = entityManager.createNamedQuery(SystemInformationData.FIND_ALL_FOR_PLATFORM_ID);
query.setParameter("platformIdent", platformId);
for (Object s : query.getResultList()) {
// we can directly remove here as objects belong to the session
// no need for merging
entityManager.remove(s);
}
query = entityManager.createNamedQuery(DefaultData.DELETE_FOR_PLATFORM_ID);
query.setParameter("platformIdent", platformId);
query.executeUpdate();
}
/**
* {@inheritDoc}
*/
@Override
public List<JmxSensorValueData> getJmxDataOverview(JmxSensorValueData template, Date fromDate, Date toDate) {
if (template == null) {
return null;
}
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<JmxSensorValueData> c = cb.createQuery(JmxSensorValueData.class);
Root<JmxSensorValueData> root = c.from(JmxSensorValueData.class);
Subquery<Long> sq = c.subquery(Long.class);
Root<JmxSensorValueData> sqRoot = sq.from(JmxSensorValueData.class);
Predicate platformIdentPredicate = cb.equal(sqRoot.get("platformIdent"), template.getPlatformIdent());
Predicate sensorTypeIdentPredicate = cb.equal(sqRoot.get("sensorTypeIdent"), template.getSensorTypeIdent());
Predicate predicate = cb.and(platformIdentPredicate, sensorTypeIdentPredicate);
if (template.getJmxSensorDefinitionDataIdentId() > 0) {
predicate = cb.and(predicate, cb.equal(sqRoot.get("jmxSensorDefinitionDataIdentId"), template.getJmxSensorDefinitionDataIdentId()));
}
if ((fromDate != null) && (toDate != null)) {
predicate = cb.and(predicate, cb.between(sqRoot.get("timeStamp").as(Date.class), fromDate, toDate));
}
sq.select(cb.max(sqRoot.get("id").as(Long.class))).where(predicate).groupBy(sqRoot.get("jmxSensorDefinitionDataIdentId"));
c.select(root).where(cb.in(root.get("id")).value(sq));
return entityManager.createQuery(c).getResultList();
}
}