mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
298 lines
8.8 KiB
Java
298 lines
8.8 KiB
Java
package com.avaje.ebeaninternal.server.loadcontext;
|
|
|
|
import com.avaje.ebean.bean.*;
|
|
import com.avaje.ebeaninternal.api.LoadContext;
|
|
import com.avaje.ebeaninternal.api.LoadSecondaryQuery;
|
|
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
|
import com.avaje.ebeaninternal.api.SpiQuery;
|
|
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
|
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
|
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
|
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
|
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
|
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
|
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Default implementation of LoadContext.
|
|
*/
|
|
public class DLoadContext implements LoadContext {
|
|
|
|
private final SpiEbeanServer ebeanServer;
|
|
|
|
private final BeanDescriptor<?> rootDescriptor;
|
|
|
|
private final Map<String, DLoadBeanContext> beanMap = new HashMap<String, DLoadBeanContext>();
|
|
private final Map<String, DLoadManyContext> manyMap = new HashMap<String, DLoadManyContext>();
|
|
|
|
private final DLoadBeanContext rootBeanContext;
|
|
|
|
private final Boolean readOnly;
|
|
private final boolean excludeBeanCache;
|
|
private final int defaultBatchSize;
|
|
|
|
/**
|
|
* The path relative to the root of the object graph.
|
|
*/
|
|
private final String relativePath;
|
|
private final ObjectGraphOrigin origin;
|
|
private final boolean useAutofetchManager;
|
|
|
|
private final Map<String,ObjectGraphNode> nodePathMap = new HashMap<String, ObjectGraphNode>();
|
|
|
|
private PersistenceContext persistenceContext;
|
|
|
|
private List<OrmQueryProperties> secQuery;
|
|
|
|
public DLoadContext(OrmQueryRequest<?> request) {
|
|
|
|
this.persistenceContext = request.getPersistenceContext();
|
|
this.ebeanServer = request.getServer();
|
|
this.defaultBatchSize = request.getLazyLoadBatchSize();
|
|
this.rootDescriptor = request.getBeanDescriptor();
|
|
|
|
SpiQuery<?> query = request.getQuery();
|
|
this.readOnly = query.isReadOnly();
|
|
this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache());
|
|
this.useAutofetchManager = query.getAutoFetchManager() != null;
|
|
|
|
ObjectGraphNode parentNode = query.getParentNode();
|
|
if (parentNode != null){
|
|
this.origin = parentNode.getOriginQueryPoint();
|
|
this.relativePath = parentNode.getPath();
|
|
} else {
|
|
this.origin = null;
|
|
this.relativePath = null;
|
|
}
|
|
|
|
// initialise rootBeanContext after origin and relativePath have been set
|
|
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
|
}
|
|
|
|
protected boolean isExcludeBeanCache() {
|
|
return excludeBeanCache;
|
|
}
|
|
|
|
/**
|
|
* Return the minimum batch size when using QueryIterator with query joins.
|
|
*/
|
|
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch) {
|
|
|
|
if (secQuery == null) {
|
|
return -1;
|
|
}
|
|
|
|
int maxBatch = 0;
|
|
for (int i = 0; i < secQuery.size(); i++) {
|
|
int batchSize = secQuery.get(i).getQueryFetchBatch();
|
|
if (batchSize == 0) {
|
|
batchSize = defaultQueryBatch;
|
|
}
|
|
maxBatch = Math.max(maxBatch, batchSize);
|
|
}
|
|
return maxBatch;
|
|
}
|
|
|
|
/**
|
|
* Execute all the secondary queries.
|
|
*/
|
|
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest) {
|
|
|
|
if (secQuery != null){
|
|
for (int i = 0; i < secQuery.size(); i++) {
|
|
OrmQueryProperties properties = secQuery.get(i);
|
|
LoadSecondaryQuery load = getLoadSecondaryQuery(properties.getPath());
|
|
load.loadSecondaryQuery(parentRequest);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the LoadBeanContext or LoadManyContext for the given path.
|
|
*/
|
|
private LoadSecondaryQuery getLoadSecondaryQuery(String path){
|
|
LoadSecondaryQuery beanLoad = beanMap.get(path);
|
|
if (beanLoad == null){
|
|
beanLoad = manyMap.get(path);
|
|
}
|
|
return beanLoad;
|
|
}
|
|
|
|
/**
|
|
* Remove the +query and +lazy secondary queries and
|
|
* register them with their appropriate LoadBeanContext
|
|
* or LoadManyContext.
|
|
* <p>
|
|
* The parts of the secondary queries are removed and used
|
|
* by LoadBeanContext/LoadManyContext to build the appropriate
|
|
* queries.
|
|
* </p>
|
|
*/
|
|
public void registerSecondaryQueries(SpiQuery<?> query) {
|
|
|
|
secQuery = query.removeQueryJoins();
|
|
if (secQuery != null){
|
|
for (int i = 0; i < secQuery.size(); i++) {
|
|
OrmQueryProperties props = secQuery.get(i);
|
|
registerSecondaryQuery(props);
|
|
}
|
|
}
|
|
|
|
List<OrmQueryProperties> lazyQueries = query.removeLazyJoins();
|
|
if (lazyQueries != null){
|
|
for (int i = 0; i < lazyQueries.size(); i++) {
|
|
OrmQueryProperties lazyProps = lazyQueries.get(i);
|
|
registerSecondaryQuery(lazyProps);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup the load context at this path with OrmQueryProperties which is
|
|
* used to build the appropriate query for +query or +lazy loading.
|
|
*/
|
|
private void registerSecondaryQuery(OrmQueryProperties props) {
|
|
|
|
String propName = props.getPath();
|
|
ElPropertyValue elGetValue = rootDescriptor.getElGetValue(propName);
|
|
|
|
boolean many = elGetValue.getBeanProperty().containsMany();
|
|
registerSecondaryNode(many, props);
|
|
}
|
|
|
|
|
|
public ObjectGraphNode getObjectGraphNode(String path) {
|
|
|
|
ObjectGraphNode node = nodePathMap.get(path);
|
|
if (node == null){
|
|
node = createObjectGraphNode(path);
|
|
nodePathMap.put(path, node);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
private ObjectGraphNode createObjectGraphNode(String path) {
|
|
|
|
if (relativePath != null){
|
|
if (path == null){
|
|
path = relativePath;
|
|
} else {
|
|
path = relativePath+"."+path;
|
|
}
|
|
}
|
|
return new ObjectGraphNode(origin, path);
|
|
}
|
|
|
|
public boolean isUseAutofetchManager() {
|
|
return useAutofetchManager;
|
|
}
|
|
|
|
protected String getFullPath(String path) {
|
|
if (relativePath == null) {
|
|
return path;
|
|
} else {
|
|
return relativePath + "." + path;
|
|
}
|
|
}
|
|
|
|
protected SpiEbeanServer getEbeanServer() {
|
|
return ebeanServer;
|
|
}
|
|
|
|
/**
|
|
* Return the parent state which defines the sharedInstance and readOnly status
|
|
* which needs to be propagated to other beans and collections.
|
|
*/
|
|
protected Boolean isReadOnly() {
|
|
return readOnly;
|
|
}
|
|
|
|
public PersistenceContext getPersistenceContext() {
|
|
return persistenceContext;
|
|
}
|
|
|
|
public void resetPersistenceContext(PersistenceContext persistenceContext) {
|
|
this.persistenceContext = persistenceContext;
|
|
// clear the load contexts for beans and beanCollections
|
|
for (DLoadBeanContext beanContext : beanMap.values()) {
|
|
beanContext.clear();
|
|
}
|
|
for (DLoadManyContext manyContext : manyMap.values()) {
|
|
manyContext.clear();
|
|
}
|
|
this.rootBeanContext.clear();
|
|
}
|
|
|
|
public void register(String path, EntityBeanIntercept ebi){
|
|
getBeanContext(path).register(ebi);
|
|
}
|
|
|
|
public void register(String path, BeanCollection<?> bc){
|
|
getManyContext(path).register(bc);
|
|
}
|
|
|
|
private DLoadBeanContext getBeanContext(String path) {
|
|
if (path == null){
|
|
return rootBeanContext;
|
|
}
|
|
DLoadBeanContext beanContext = beanMap.get(path);
|
|
if (beanContext == null){
|
|
beanContext = createBeanContext(path, defaultBatchSize, null);
|
|
beanMap.put(path, beanContext);
|
|
}
|
|
return beanContext;
|
|
}
|
|
|
|
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
|
|
|
|
String path = props.getPath();
|
|
int lazyJoinBatch = props.getLazyFetchBatch();
|
|
int batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize;
|
|
|
|
if (many){
|
|
DLoadManyContext manyContext = createManyContext(path, batchSize, props);
|
|
manyMap.put(path, manyContext);
|
|
} else {
|
|
DLoadBeanContext beanContext = createBeanContext(path, batchSize, props);
|
|
beanMap.put(path, beanContext);
|
|
}
|
|
}
|
|
|
|
private DLoadManyContext getManyContext(String path) {
|
|
if (path == null){
|
|
throw new RuntimeException("path is null?");
|
|
}
|
|
DLoadManyContext ctx = manyMap.get(path);
|
|
if (ctx == null){
|
|
ctx = createManyContext(path, defaultBatchSize, null);
|
|
manyMap.put(path, ctx);
|
|
}
|
|
return ctx;
|
|
}
|
|
|
|
private DLoadManyContext createManyContext(String path, int batchSize, OrmQueryProperties queryProps) {
|
|
|
|
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>)getBeanProperty(rootDescriptor, path);
|
|
|
|
return new DLoadManyContext(this, p, path, batchSize, queryProps);
|
|
}
|
|
|
|
private DLoadBeanContext createBeanContext(String path, int batchSize, OrmQueryProperties queryProps) {
|
|
|
|
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>)getBeanProperty(rootDescriptor, path);
|
|
BeanDescriptor<?> targetDescriptor = p.getTargetDescriptor();
|
|
|
|
return new DLoadBeanContext(this, targetDescriptor, path, batchSize, queryProps);
|
|
}
|
|
|
|
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path){
|
|
return desc.getBeanPropertyFromPath(path);
|
|
}
|
|
|
|
}
|