package fr.openwide.core.jpa.externallinkchecker.business.dao;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.querydsl.core.types.dsl.DateExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQuery;
import fr.openwide.core.jpa.business.generic.dao.GenericEntityDaoImpl;
import fr.openwide.core.jpa.externallinkchecker.business.model.ExternalLinkStatus;
import fr.openwide.core.jpa.externallinkchecker.business.model.ExternalLinkWrapper;
import fr.openwide.core.jpa.externallinkchecker.business.model.QExternalLinkWrapper;
@Service("externalLinkWrapperDao")
public class ExternalLinkWrapperDaoImpl extends GenericEntityDaoImpl<Long, ExternalLinkWrapper> implements IExternalLinkWrapperDao {
private static final QExternalLinkWrapper qExternalLinkWrapper = QExternalLinkWrapper.externalLinkWrapper;
@Override
public List<ExternalLinkWrapper> listByIds(Collection<Long> ids) {
if (ids == null || ids.isEmpty()) {
return Lists.newArrayList();
}
return new JPAQuery<ExternalLinkWrapper>(getEntityManager()).from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.id.in(ids))
.orderBy(qExternalLinkWrapper.id.asc())
.fetch();
}
@Override
public List<ExternalLinkWrapper> listActive() {
JPQLQuery<ExternalLinkWrapper> query = new JPAQuery<>(getEntityManager());
query.from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.status.notIn(ExternalLinkStatus.INACTIVES))
.orderBy(qExternalLinkWrapper.url.lower().asc());
return query.fetch();
}
@Override
public List<ExternalLinkWrapper> listNextCheckingBatch(int batchSize, int minDelayBetweenTwoChecks) {
JPQLQuery<ExternalLinkWrapper> query = new JPAQuery<>(getEntityManager());
// Query to list the next <batchsize> URLs
// Must be a separate query, not a subquery, since JPQL doesn't support limit in subqueries
List<String> nextUrlsToCheckSubquery = listNextCheckingBatchUrls(batchSize, minDelayBetweenTwoChecks);
if (nextUrlsToCheckSubquery.isEmpty()) {
return Lists.newArrayListWithCapacity(0);
}
// Query to list the matching linkwrappers (may be more than <batchsize>)
query.from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.url.lower().in(nextUrlsToCheckSubquery))
// Only links without the following statuses are to be checked
.where(qExternalLinkWrapper.status.notIn(ExternalLinkStatus.INACTIVES))
.orderBy(qExternalLinkWrapper.id.asc());
return query.fetch();
}
private List<String> listNextCheckingBatchUrls(int batchSize, int minDelayBetweenTwoChecks) {
JPQLQuery<String> query = new JPAQuery<String>(getEntityManager())
.select(qExternalLinkWrapper.url.lower())
.from(qExternalLinkWrapper);
StringExpression url = qExternalLinkWrapper.url.lower();
query
// Only links with the following statuses are to be checked
.where(qExternalLinkWrapper.status.notIn(ExternalLinkStatus.INACTIVES))
.groupBy(url)
.orderBy(
// NOTE: if, for a given URL, one linkWrapper has a null lastCheckDate and the other has a non-null lastCheckDate, the null one is ignored.
// This is not really on purpose, but this does not impair functionality and the implementation is simpler that way.
qExternalLinkWrapper.lastCheckDate.max().asc().nullsFirst(),
url.asc()
);
if (minDelayBetweenTwoChecks > 0) {
DateExpression<Date> nowMinusMinDelay = Expressions.dateTemplate(Date.class,
"NOW() - interval({0}) - interval('8 hours')", minDelayBetweenTwoChecks + " days");
query.where(qExternalLinkWrapper.lastCheckDate.isNull()
.or(qExternalLinkWrapper.lastCheckDate.before(nowMinusMinDelay)));
}
return query.limit(batchSize).fetch();
}
@Override
public List<String> listUrlsFromIds(Collection<Long> ids) {
return new JPAQuery<String>(getEntityManager())
.select(qExternalLinkWrapper.url)
.from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.id.in(ids))
.orderBy(qExternalLinkWrapper.url.asc())
.distinct()
.fetch();
}
@Override
public List<String> listUrlsFromStatuses(Collection<ExternalLinkStatus> statuses) {
return new JPAQuery<String>(getEntityManager())
.select(qExternalLinkWrapper.url)
.from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.status.in(statuses))
.orderBy(qExternalLinkWrapper.url.asc())
.distinct()
.fetch();
}
@Override
public List<ExternalLinkWrapper> listFromUrls(Collection<String> urls) {
Set<String> lowerUrls = Sets.newHashSet();
for (String url : urls) {
lowerUrls.add(StringUtils.lowerCase(url));
}
return new JPAQuery<ExternalLinkWrapper>(getEntityManager())
.from(qExternalLinkWrapper)
.where(qExternalLinkWrapper.url.lower().in(lowerUrls))
.orderBy(qExternalLinkWrapper.id.asc())
.fetch();
}
}