package io.ebeaninternal.server.loadcontext;
import io.ebean.CacheMode;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.LoadBeanBuffer;
import io.ebeaninternal.api.LoadBeanContext;
import io.ebeaninternal.api.LoadBeanRequest;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
private final boolean cache;
private List<LoadBuffer> bufferList;
private LoadBuffer currentBuffer;
DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
super(parent, desc, path, defaultBatchSize, queryProps);
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
this.currentBuffer = createBuffer(firstBatchSize);
this.cache = (queryProps != null) && queryProps.isCache();
}
@Override
public void register(BeanPropertyAssocMany<?> many, BeanCollection<?> collection) {
String path = fullPath + "." + many.getName();
parent.register(path, many, collection);
}
public void clear() {
if (bufferList != null) {
bufferList.clear();
}
currentBuffer = createBuffer(secondaryBatchSize);
}
private void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
if (cache) {
query.setBeanCacheMode(CacheMode.ON);
}
setLabel(query);
parent.propagateQueryState(query, desc.isDocStoreMapped());
query.setParentNode(objectGraphNode);
query.setLazyLoadProperty(lazyLoadProperty);
if (queryProps != null) {
queryProps.configureBeanQuery(query);
}
}
protected void register(EntityBeanIntercept ebi) {
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(secondaryBatchSize);
}
ebi.setBeanLoader(currentBuffer, getPersistenceContext());
currentBuffer.add(ebi);
}
private LoadBuffer createBuffer(int size) {
LoadBuffer buffer = new LoadBuffer(this, size);
if (bufferList != null) {
bufferList.add(buffer);
}
return buffer;
}
@Override
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
}
lock.lock();
try {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
if (!queryProps.isQueryFetchAll()) {
break;
}
}
if (forEach) {
clear();
} else {
this.bufferList = null;
}
}
}
} finally {
lock.unlock();
}
}
static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
private final ReentrantLock bufferLock = new ReentrantLock();
private final DLoadBeanContext context;
private final int batchSize;
private final List<EntityBeanIntercept> list;
private PersistenceContext persistenceContext;
LoadBuffer(DLoadBeanContext context, int batchSize) {
this.context = context;
this.batchSize = batchSize;
this.list = new ArrayList<>(batchSize);
}
@Override
public Lock lock() {
bufferLock.lock();
return bufferLock;
}
@Override
public int getBatchSize() {
return batchSize;
}
public boolean isFull() {
return batchSize == list.size();
}
public void add(EntityBeanIntercept ebi) {
if (persistenceContext == null) {
persistenceContext = ebi.getPersistenceContext();
}
list.add(ebi);
}
@Override
public List<EntityBeanIntercept> getBatch() {
return list;
}
@Override
public String getName() {
return context.serverName;
}
@Override
public String getFullPath() {
return context.fullPath;
}
@Override
public BeanDescriptor<?> getBeanDescriptor() {
return context.desc;
}
@Override
public PersistenceContext getPersistenceContext() {
return persistenceContext;
}
@Override
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
context.configureQuery(query, lazyLoadProperty);
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
if (context.desc.lazyLoadMany(ebi, context)) {
return;
}
if (context.hitCache) {
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(list, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
list.removeAll(hits);
if (list.isEmpty() || hits.contains(ebi)) {
return;
}
}
LoadBeanRequest req = new LoadBeanRequest(this, ebi, context.hitCache);
context.desc.getEbeanServer().loadBean(req);
list.clear();
}
}
}