org.javers.repository.jql.ShadowStreamQueryRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javers-core Show documentation
Show all versions of javers-core Show documentation
JaVers - object auditing and diff framework for Java
package org.javers.repository.jql;
import org.javers.common.collections.Lists;
import org.javers.common.validation.Validate;
import org.javers.core.metamodel.object.CdoSnapshot;
import org.javers.shadow.Shadow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Spliterator.IMMUTABLE;
import static java.util.Spliterator.ORDERED;
import static org.javers.repository.jql.ShadowQueryRunner.*;
class ShadowStreamQueryRunner {
private static final Logger logger = LoggerFactory.getLogger(JqlQuery.JQL_LOGGER_NAME);
private final ShadowQueryRunner shadowQueryRunner;
private final QueryCompiler queryCompiler;
public ShadowStreamQueryRunner(ShadowQueryRunner shadowQueryRunner, QueryCompiler queryCompiler) {
this.shadowQueryRunner = shadowQueryRunner;
this.queryCompiler = queryCompiler;
}
Stream queryForShadowsStream(JqlQuery query) {
int shadowsLimit = query.getQueryParams().limit();
int shadowsSkip = query.getQueryParams().skip();
int characteristics = IMMUTABLE | ORDERED;
StreamQuery streamQuery = new StreamQuery(query, shadowsLimit);
Spliterator spliterator = Spliterators
.spliteratorUnknownSize(streamQuery.lazyIterator(), characteristics);
Stream stream = StreamSupport.stream(spliterator, false);
if (shadowsSkip > 0) {
stream = stream.skip(shadowsSkip);
}
query.setShadowQueryRunnerStats(streamQuery.streamStats);
return stream;
}
private class StreamQuery {
private JqlQuery awaitingQuery;
private ShadowStreamStats streamStats = new ShadowStreamStats();
private final List filledGapsSnapshots = new ArrayList<>();
private final int snapshotBatchSize;
private final int shadowsLimit;
StreamQuery(JqlQuery initialQuery, int shadowsLimit) {
Validate.argumentIsNotNull(initialQuery);
this.snapshotBatchSize = initialQuery.getQueryParams().snapshotQueryLimit().orElse(100);
queryCompiler.compile(initialQuery); //not nice, but required by changeToAggregated
initialQuery.changeToAggregatedIfEntityQuery();
this.awaitingQuery = initialQuery.changeLimit(this.snapshotBatchSize, 0);
this.shadowsLimit = shadowsLimit;
}
List loadNextPage() {
JqlQuery currentQuery = awaitingQuery;
ShadowQueryResult result = shadowQueryRunner.queryForShadows(currentQuery, filledGapsSnapshots);
logger.debug("Shadow stream query (frame " +(streamStats.size()+1)+") executed:\nJqlQuery {\n" +
" "+currentQuery.getFilterDefinition() + "\n"+
" "+currentQuery.getQueryParams() + "\n" +
" shadowScope: "+currentQuery.getShadowScope() + "\n" +
" "+result.getQueryStats() + "\n" +
"}");
streamStats.addNextFrameStats(result.getQueryStats());
filledGapsSnapshots.addAll(result.getFilledGapsSnapshots());
awaitingQuery = currentQuery.nextQueryForStream();
return result.getShadows();
}
Iterator lazyIterator() {
return new LazyIterator();
}
class LazyIterator implements Iterator {
private boolean terminated = false;
Deque shadowsToGo = new ArrayDeque<>();
private int nextIdx = 0;
private boolean noMorePages;
@Override
public boolean hasNext() {
if (nextIdx == shadowsLimit) {
terminate();
return false;
}
if (shadowsToGo.size() > 0) {
return true;
} else {
if (noMorePages) {
return false;
}
else {
List nextPage = loadNextPage();
if (nextPage.size() < snapshotBatchSize) {
noMorePages = true;
}
if (nextPage.size() == 0) {
terminate();
return false;
} else {
shadowsToGo.addAll(nextPage);
}
return true;
}
}
}
private void terminate() {
shadowsToGo.clear();
terminated = true;
}
@Override
public Shadow next() {
if (terminated) {
throw new IllegalStateException("attempt to read from the terminated iterator");
}
Shadow result = shadowsToGo.poll();
nextIdx++;
return result;
}
}
}
public static class ShadowStreamStats extends ShadowStats {
private final List frameQueriesStats = new ArrayList<>();
void addNextFrameStats(ShadowStats next) {
this.frameQueriesStats.add(next);
}
int size() {
return frameQueriesStats.size();
}
ShadowStats getFirstFrameStats() {
if (frameQueriesStats.isEmpty()) {
return null;
}
return frameQueriesStats.get(0);
}
public List getFrameQueriesStats() {
return Collections.unmodifiableList(frameQueriesStats);
}
@Override
List