package rocks.inspectit.server.dao.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.persistence.TypedQuery;
import org.apache.commons.collections.CollectionUtils;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import rocks.inspectit.server.dao.PlatformIdentDao;
import rocks.inspectit.server.util.PlatformIdentCache;
import rocks.inspectit.shared.all.cmr.model.MethodIdent;
import rocks.inspectit.shared.all.cmr.model.PlatformIdent;
/**
* The default implementation of the {@link PlatformIdentDao} interface by using the Entity manager.
*
* @author Patrice Bouillet
*
*/
@Repository
public class PlatformIdentDaoImpl extends AbstractJpaDao<PlatformIdent> implements PlatformIdentDao {
/**
* {@link PlatformIdent} cache.
*/
@Autowired
private PlatformIdentCache platformIdentCache;
/**
* Transaction template to use to do init work.
*/
private TransactionTemplate tt;
/**
* Default constructor.
* <p>
* Needs {@link PlatformTransactionManager} for instantiating the {@link TransactionTemplate} to
* execute the initialization.
*
* @param transactionManager
* {@link PlatformTransactionManager}. Autowired by Spring.
*/
@Autowired
public PlatformIdentDaoImpl(PlatformTransactionManager transactionManager) {
super(PlatformIdent.class);
this.tt = new TransactionTemplate(transactionManager);
}
/**
* {@inheritDoc}
*
*/
@Override
public void delete(PlatformIdent platformIdent) {
super.delete(platformIdent);
platformIdentCache.remove(platformIdent);
}
/**
* {@inheritDoc}
*/
@Override
public void deleteAll(List<PlatformIdent> platformIdents) {
for (PlatformIdent platformIdent : platformIdents) {
delete(platformIdent);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<PlatformIdent> findAll() {
return getEntityManager().createNamedQuery(PlatformIdent.FIND_ALL, PlatformIdent.class).getResultList();
}
/**
* {@inheritDoc}
*/
@Override
public List<PlatformIdent> findByName(String agentName) {
return findByNameAndIps(agentName, null);
}
/**
* {@inheritDoc}
*/
@Override
public List<PlatformIdent> findByNameAndIps(String agentName, List<String> definedIps) {
TypedQuery<PlatformIdent> query = getEntityManager().createNamedQuery(PlatformIdent.FIND_BY_AGENT_NAME, PlatformIdent.class);
query.setParameter("agentName", agentName);
List<PlatformIdent> results = query.getResultList();
// manually filter the defined IPs
if (null != definedIps) {
for (Iterator<PlatformIdent> it = results.iterator(); it.hasNext();) {
PlatformIdent platformIdent = it.next();
if (!Objects.equals(definedIps, platformIdent.getDefinedIPs())) {
it.remove();
}
}
}
return results;
}
/**
* {@inheritDoc}
*/
@Override
public void saveOrUpdate(PlatformIdent platformIdent) {
final int maxDefIPsSize = 1024;
if (null != platformIdent.getDefinedIPs()) {
int charNum = 0;
List<String> newDefinedIPs = new ArrayList<>();
for (String item : platformIdent.getDefinedIPs()) {
// if it is too long, we stop adding
if ((charNum + item.length()) <= maxDefIPsSize) {
newDefinedIPs.add(item);
// we add 1 also for the white space
charNum += item.length() + 1;
} else {
break;
}
}
// change only if we really cut the list
if (newDefinedIPs.size() != platformIdent.getDefinedIPs().size()) {
platformIdent.setDefinedIPs(newDefinedIPs);
}
}
if (null == platformIdent.getId()) {
super.create(platformIdent);
} else {
super.update(platformIdent);
}
platformIdentCache.markDirty(platformIdent);
}
/**
* {@inheritDoc}
*/
@Override
public PlatformIdent findInitialized(long id) {
for (PlatformIdent platformIdent : platformIdentCache.getCleanPlatformIdents()) {
if (platformIdent.getId().longValue() == id) {
return platformIdent;
}
}
List<PlatformIdent> cleanPlatformIdents = loadIdentsFromDB(Collections.singleton(Long.valueOf(id)));
if (CollectionUtils.isNotEmpty(cleanPlatformIdents)) {
if (1 == cleanPlatformIdents.size()) {
return cleanPlatformIdents.get(0);
} else {
throw new RuntimeException("More than one agent retrieved for one ID.");
}
}
return null;
}
/**
* Find all initialized agents that have a id in a given set.
*
* @param wantedAgentsIds
* Agents Ids.
* @return List of {@link PlatformIdent}.
*/
public List<PlatformIdent> findAllInitialized(Set<Long> wantedAgentsIds) {
if (null == wantedAgentsIds) {
return Collections.emptyList();
}
List<PlatformIdent> initializedPlatformIdents = new ArrayList<>();
List<Long> cleanIdents = new ArrayList<>();
for (PlatformIdent platformIdent : platformIdentCache.getCleanPlatformIdents()) {
cleanIdents.add(platformIdent.getId());
if (wantedAgentsIds.contains(platformIdent.getId())) {
initializedPlatformIdents.add(platformIdent);
}
}
wantedAgentsIds.removeAll(cleanIdents);
if (CollectionUtils.isNotEmpty(wantedAgentsIds)) {
List<PlatformIdent> cleanPlatformIdents = loadIdentsFromDB(wantedAgentsIds);
for (PlatformIdent platformIdent : cleanPlatformIdents) {
if (wantedAgentsIds.contains(platformIdent.getId())) {
initializedPlatformIdents.add(platformIdent);
}
}
}
Collections.sort(initializedPlatformIdents, new Comparator<PlatformIdent>() {
@Override
public int compare(PlatformIdent o1, PlatformIdent o2) {
return (int) (o1.getId().longValue() - o2.getId().longValue());
}
});
return initializedPlatformIdents;
}
/**
* Initialize all platform idents from the database.
*/
@PostConstruct
public void postConstruct() {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// load all non-fetched and collect ids
List<PlatformIdent> allNonFetched = findAll();
if (CollectionUtils.isNotEmpty(allNonFetched)) {
Collection<Long> toLoad = new ArrayList<>(allNonFetched.size());
for (PlatformIdent platformIdent : allNonFetched) {
toLoad.add(platformIdent.getId());
}
loadIdentsFromDB(toLoad);
}
}
});
}
/**
* Loads complete agents from database.
*
* @param ids
* IDs of the agents that should be loaded.
*
* @return List of {@link PlatformIdent}.
*/
private List<PlatformIdent> loadIdentsFromDB(Collection<Long> ids) {
// check if there s anything to load
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyList();
}
List<PlatformIdent> platformIdents = new ArrayList<>();
for (Long id : ids) {
PlatformIdent platformIdent = load(id);
if (null != platformIdent) {
Hibernate.initialize(platformIdent.getSensorTypeIdents());
Hibernate.initialize(platformIdent.getJmxDefinitionDataIdents());
Hibernate.initialize(platformIdent.getMethodIdents());
for (MethodIdent methodIdent : platformIdent.getMethodIdents()) {
Hibernate.initialize(methodIdent.getMethodIdentToSensorTypes());
}
platformIdents.add(platformIdent);
}
}
// mark all as clean
for (PlatformIdent platformIdent : platformIdents) {
platformIdentCache.markClean(platformIdent);
}
return platformIdents;
}
}