package rocks.inspectit.server.processor.impl;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import rocks.inspectit.server.dao.impl.TimerDataAggregator;
import rocks.inspectit.server.processor.AbstractCmrDataProcessor;
import rocks.inspectit.shared.all.communication.DefaultData;
import rocks.inspectit.shared.all.communication.data.HttpInfo;
import rocks.inspectit.shared.all.communication.data.HttpTimerData;
import rocks.inspectit.shared.all.communication.data.TimerData;
import rocks.inspectit.shared.all.serializer.SerializationException;
import rocks.inspectit.shared.all.serializer.impl.SerializationManager;
import rocks.inspectit.shared.all.serializer.provider.SerializationManagerProvider;
import rocks.inspectit.shared.all.spring.logger.Log;
/**
* Processor that saves {@link TimerData} or {@link HttpTimerData} to database correctly if the
* charting is on.
*
* @author Ivan Senic
*
*/
public class TimerDataChartingCmrProcessor extends AbstractCmrDataProcessor {
/**
* Log for this class.
*/
@Log
Logger log;
/**
* {@link TimerDataAggregator} for {@link TimerData} aggregation.
*/
@Autowired
TimerDataAggregator timerDataAggregator;
/**
* Serialization manager provider for getting the {@link SerializationManager}.
*/
@Autowired
private SerializationManagerProvider serializationManagerProvider;
/**
* If writing to the influxDB is active. In that case we will not persist anything to the
* relational database.
*/
@Value("${influxdb.active}")
boolean influxActive;
/**
* {@link SerializationManager} for cloning.
*/
SerializationManager serializationManager;
/**
* {@inheritDoc}
*/
@Override
protected void processData(DefaultData defaultData, EntityManager entityManager) {
if (defaultData instanceof HttpTimerData) {
try {
HttpTimerData original = (HttpTimerData) defaultData;
HttpInfo httpInfo = getHttpInfo(original, entityManager);
HttpTimerData clone = getClone(original);
clone.setHttpInfo(httpInfo);
entityManager.persist(clone);
} catch (SerializationException e) {
log.warn("TimerDataChartingCmrProcessor failed to clone the given HttpTimerData", e);
}
} else {
timerDataAggregator.processTimerData((TimerData) defaultData);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean canBeProcessed(DefaultData defaultData) {
return !influxActive && (defaultData instanceof TimerData) && ((TimerData) defaultData).isCharting();
}
/**
* Creates the cloned {@link HttpTimerData} by using the kryo and {@link #serializationManager}.
* Sets id of the clone to zero.
*
* @param original
* Data to be cloned.
* @return Cloned {@link HttpTimerData} with id zero.
* @throws SerializationException
* If serialization fails.
*/
private synchronized HttpTimerData getClone(HttpTimerData original) throws SerializationException {
HttpTimerData httpTimerData = serializationManager.copy(original);
httpTimerData.setId(0L);
return httpTimerData;
}
/**
* Find {@link HttpInfo} to attach to {@link HttpTimerData} when saving.
*
* @param httpTimerData
* {@link HttpTimerData} to find info for.
* @param entityManager
* EntityManager
* @return {@link HttpInfo}.
*/
private HttpInfo getHttpInfo(HttpTimerData httpTimerData, EntityManager entityManager) {
HttpInfo httpInfo = httpTimerData.getHttpInfo();
String uri = httpInfo.isUriDefined() ? httpInfo.getUri() : null; // NOPMD
String tag = httpInfo.hasInspectItTaggingHeader() ? httpInfo.getInspectItTaggingHeaderValue() : null; // NOPMD
String requestMethod = httpInfo.getRequestMethod();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<HttpInfo> criteria = builder.createQuery(HttpInfo.class);
Root<? extends HttpInfo> root = criteria.from(HttpInfo.class);
Predicate uriPredicate;
Predicate tagPredicate;
Predicate requestMethodPredicate = builder.equal(root.get("requestMethod"), requestMethod);
if (null != uri) {
uriPredicate = builder.equal(root.get("uri"), uri);
} else {
uriPredicate = builder.isNull(root.get("uri"));
}
if (null != tag) {
tagPredicate = builder.equal(root.get("inspectItTaggingHeaderValue"), tag);
} else {
tagPredicate = builder.isNull(root.get("inspectItTaggingHeaderValue"));
}
criteria.where(uriPredicate, tagPredicate, requestMethodPredicate);
List<?> httpInfoList = entityManager.createQuery(criteria).getResultList();
if (CollectionUtils.isNotEmpty(httpInfoList)) {
return (HttpInfo) httpInfoList.get(0);
} else {
return new HttpInfo(uri, requestMethod, tag);
}
}
/**
* Post construct.
*/
@PostConstruct
protected void init() {
serializationManager = serializationManagerProvider.createSerializer();
}
}