Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.ebeaninternal.server.deploy;
import io.ebean.*;
import io.ebean.annotation.DocStoreMode;
import io.ebean.bean.*;
import io.ebean.cache.QueryCacheEntry;
import io.ebean.DatabaseBuilder;
import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.event.*;
import io.ebean.event.changelog.BeanChange;
import io.ebean.event.changelog.ChangeLogFilter;
import io.ebean.event.changelog.ChangeType;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.event.readaudit.ReadEvent;
import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.MetricVisitor;
import io.ebean.meta.QueryPlanInit;
import io.ebean.plugin.BeanDocType;
import io.ebean.plugin.BeanType;
import io.ebean.plugin.ExpressionPath;
import io.ebean.plugin.Property;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.*;
import io.ebeaninternal.api.TransactionEventTable.TableIUD;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.cache.CacheChangeSet;
import io.ebeaninternal.server.cache.CachedBeanData;
import io.ebeaninternal.server.cache.CachedManyIds;
import io.ebeaninternal.server.core.*;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.deploy.id.IdBinderSimple;
import io.ebeaninternal.server.deploy.id.ImportedId;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyLists;
import io.ebeaninternal.server.el.*;
import io.ebeaninternal.server.persist.DeleteMode;
import io.ebeaninternal.server.query.*;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.util.SortByClause;
import io.ebeaninternal.util.SortByClauseParser;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
import io.ebeanservice.docstore.api.DocStoreUpdateContext;
import io.ebeanservice.docstore.api.DocStoreUpdates;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import javax.persistence.PersistenceException;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.sql.Types;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
import static java.lang.System.Logger.Level.ERROR;
import static java.lang.System.Logger.Level.INFO;
/**
* Describes Beans including their deployment information.
*/
public class BeanDescriptor implements BeanType, STreeType, SpiBeanType {
private static final System.Logger log = CoreLog.internal;
public enum EntityType {
ORM, EMBEDDED, VIEW, SQL, DOC
}
private final ConcurrentHashMap updatePlanCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap queryPlanCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap elCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap elDeployCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap> comparatorCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap dynamicProperty = new ConcurrentHashMap<>();
private final ConcurrentHashMap> pathMaps = new ConcurrentHashMap<>();
private final Map namedRawSql;
private final Map namedQuery;
private final boolean multiValueSupported;
private boolean batchEscalateOnCascadeInsert;
private boolean batchEscalateOnCascadeDelete;
private final BeanIudMetrics iudMetrics;
private final EntityType entityType;
/**
* Set when Id property is marked with GeneratedValue annotation.
*/
private final boolean idGeneratedValue;
private final PlatformIdGenerator idGenerator;
private final IdentityMode identityMode;
private final IdType idType;
/**
* SQL used to return last inserted id. Used for Identity columns where
* getGeneratedKeys is not supported.
*/
private final String selectLastInsertedId;
private final String selectLastInsertedIdDraft;
private final boolean autoTunable;
private final ConcurrencyMode concurrencyMode;
private final IndexDefinition[] indexDefinitions;
private final String[] dependentTables;
private final String baseTable;
private final String baseTableAsOf;
private final String baseTableVersionsBetween;
private final boolean historySupport;
private final TableJoin primaryKeyJoin;
private final BeanProperty softDeleteProperty;
private final boolean softDelete;
private final String draftTable;
private final PartitionMeta partitionMeta;
private final TablespaceMeta tablespaceMeta;
private final String storageEngine;
private final String dbComment;
private final boolean readAuditing;
private final boolean draftable;
private final boolean draftableElement;
private final BeanProperty unmappedJson;
private final BeanProperty tenant;
private final BeanProperty draft;
private final BeanProperty draftDirty;
private final LinkedHashMap propMap;
/**
* Map of DB column to property path (for nativeSql mapping).
*/
private final Map columnPath = new HashMap<>();
/**
* Map of related table to assoc property (for nativeSql mapping).
*/
private final Map> tablePath = new HashMap<>();
final Class beanType;
final Class> rootBeanType;
private final BeanDescriptorMap owner;
final String[] properties;
private final BeanPostLoad beanPostLoad;
private final BeanPostConstructListener beanPostConstructListener;
private volatile BeanPersistController persistController;
private volatile BeanPersistListener persistListener;
private final BeanQueryAdapter queryAdapter;
private final BeanFindController beanFinder;
private final ChangeLogFilter changeLogFilter;
final InheritInfo inheritInfo;
private final boolean abstractType;
private final BeanProperty idProperty;
private final int idPropertyIndex;
private final BeanProperty versionProperty;
private final int versionPropertyIndex;
private final BeanProperty whenModifiedProperty;
private final BeanProperty whenCreatedProperty;
/**
* Properties that are initialised in the constructor need to be 'unloaded' to support partial object queries.
*/
private final int[] unloadProperties;
/**
* Properties local to this type (not from a super type).
*/
private final BeanProperty[] propertiesLocal;
/**
* Scalar mutable properties (need to dirty check on update).
*/
private final BeanProperty[] propertiesMutable;
private final BeanPropertyAssocOne> unidirectional;
private final BeanProperty orderColumn;
private final BeanProperty[] propertiesNonMany;
private final BeanProperty[] propertiesAggregate;
private final BeanPropertyAssocMany>[] propertiesMany;
private final BeanPropertyAssocMany>[] propertiesManySave;
private final BeanPropertyAssocMany>[] propertiesManyDelete;
private final BeanPropertyAssocMany>[] propertiesManyToMany;
/**
* list of properties that are associated beans and not embedded (Derived).
*/
private final BeanPropertyAssocOne>[] propertiesOne;
private final BeanPropertyAssocOne>[] propertiesOneImported;
private final BeanPropertyAssocOne>[] propertiesOneImportedSave;
private final BeanPropertyAssocOne>[] propertiesOneImportedDelete;
private final BeanPropertyAssocOne>[] propertiesOneExportedSave;
private final BeanPropertyAssocOne>[] propertiesOneExportedDelete;
private final BeanPropertyAssocOne>[] propertiesEmbedded;
private final BeanProperty[] propertiesBaseScalar;
private final BeanProperty[] propertiesTransient;
/**
* All non transient properties excluding the id properties.
*/
private final BeanProperty[] propertiesNonTransient;
final BeanProperty[] propertiesIndex;
private final BeanProperty[] propertiesGenInsert;
private final BeanProperty[] propertiesGenUpdate;
private final List propertiesUnique = new ArrayList<>();
private final boolean idOnlyReference;
private BeanNaturalKey beanNaturalKey;
private final String fullName;
private boolean saveRecurseSkippable;
private boolean deleteRecurseSkippable;
private final EntityBean prototypeEntityBean;
private final IdBinder idBinder;
private String idBinderInLHSSql;
private String idBinderIdSql;
private String deleteByIdSql;
private String deleteByIdInSql;
private String whereIdInSql;
private String softDeleteByIdSql;
private String softDeleteByIdInSql;
private final String name;
private final String baseTableAlias;
private final boolean cacheSharableBeans;
private final String docStoreQueueId;
private final BeanDescriptorDraftHelp draftHelp;
private final BeanDescriptorCacheHelp cacheHelp;
private final BeanDescriptorJsonHelp jsonHelp;
private DocStoreBeanAdapter docStoreAdapter;
private DocumentMapping docMapping;
private boolean docStoreEmbeddedInvalidation;
private final String defaultSelectClause;
private SpiEbeanServer ebeanServer;
public BeanDescriptor(BeanDescriptorMap owner, DeployBeanDescriptor deploy) {
this.owner = owner;
this.multiValueSupported = owner.isMultiValueSupported();
this.entityType = deploy.getEntityType();
this.properties = deploy.propertyNames();
this.name = InternString.intern(deploy.getName());
this.baseTableAlias = "t0";
this.fullName = InternString.intern(deploy.getFullName());
this.beanType = deploy.getBeanType();
this.rootBeanType = PersistenceContextUtil.root(beanType);
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
this.iudMetrics = new BeanIudMetrics(name);
this.namedQuery = deploy.getNamedQuery();
this.namedRawSql = deploy.getNamedRawSql();
this.inheritInfo = deploy.getInheritInfo();
this.beanFinder = deploy.getBeanFinder();
this.persistController = deploy.getPersistController();
this.persistListener = deploy.getPersistListener();
this.beanPostConstructListener = deploy.getPostConstructListener();
this.beanPostLoad = deploy.getPostLoad();
this.queryAdapter = deploy.getQueryAdapter();
this.changeLogFilter = deploy.getChangeLogFilter();
this.defaultSelectClause = deploy.getDefaultSelectClause();
this.identityMode = deploy.buildIdentityMode();
this.idType = identityMode.getIdType();
this.idGeneratedValue = deploy.isIdGeneratedValue();
this.idGenerator = deploy.getIdGenerator();
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft();
this.concurrencyMode = deploy.getConcurrencyMode();
this.indexDefinitions = deploy.getIndexDefinitions();
this.readAuditing = deploy.isReadAuditing();
this.draftable = deploy.isDraftable();
this.draftableElement = deploy.isDraftableElement();
this.historySupport = deploy.isHistorySupport();
this.draftTable = deploy.getDraftTable();
this.baseTable = InternString.intern(deploy.getBaseTable());
this.baseTableAsOf = deploy.getBaseTableAsOf();
this.primaryKeyJoin = deploy.getPrimaryKeyJoin();
this.baseTableVersionsBetween = deploy.getBaseTableVersionsBetween();
this.dependentTables = deploy.getDependentTables();
this.dbComment = deploy.getDbComment();
this.partitionMeta = deploy.getPartitionMeta();
this.tablespaceMeta = deploy.getTablespaceMeta();
this.storageEngine = deploy.getStorageEngine();
this.autoTunable = entityType == EntityType.ORM || entityType == EntityType.VIEW;
// helper object used to derive lists of properties
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
// if formula is set, the property is virtual only (there is no column in db) the formula must evaluate to true,
// if there is a join to a deleted bean. Example: '@Formula(select = "${ta}.user_id is null")'
// this is required to support markAsDelete on beans that may have no FK constraint.
this.softDelete = (softDeleteProperty != null && !softDeleteProperty.isFormula());
this.idProperty = listHelper.getId();
this.versionProperty = listHelper.getVersionProperty();
this.unmappedJson = listHelper.getUnmappedJson();
this.tenant = listHelper.getTenant();
this.draft = listHelper.getDraft();
this.draftDirty = listHelper.getDraftDirty();
this.propMap = listHelper.getPropertyMap();
this.propertiesTransient = listHelper.getTransients();
this.propertiesNonTransient = listHelper.getNonTransients();
this.propertiesBaseScalar = listHelper.getBaseScalar();
this.propertiesEmbedded = listHelper.getEmbedded();
this.propertiesLocal = listHelper.getLocal();
this.propertiesMutable = listHelper.getMutable();
this.unidirectional = listHelper.getUnidirectional();
this.orderColumn = listHelper.getOrderColumn();
this.propertiesOne = listHelper.getOnes();
this.propertiesOneExportedSave = listHelper.getOneExportedSave();
this.propertiesOneExportedDelete = listHelper.getOneExportedDelete();
this.propertiesOneImported = listHelper.getOneImported();
this.propertiesOneImportedSave = listHelper.getOneImportedSave();
this.propertiesOneImportedDelete = listHelper.getOneImportedDelete();
this.propertiesMany = listHelper.getMany();
this.propertiesNonMany = listHelper.getNonMany();
this.propertiesAggregate = listHelper.getAggregates();
this.propertiesManySave = listHelper.getManySave();
this.propertiesManyDelete = listHelper.getManyDelete();
this.propertiesManyToMany = listHelper.getManyToMany();
this.propertiesGenInsert = listHelper.getGeneratedInsert();
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
this.idOnlyReference = isIdOnlyReference(propertiesBaseScalar);
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.cacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = initJsonHelp();
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
this.docStoreQueueId = docStoreAdapter.queueId();
// Check if there are no cascade save associated beans ( subject to change
// in initialiseOther()). Note that if we are in an inheritance hierarchy
// then we also need to check every BeanDescriptors in the InheritInfo as
// well. We do that later in initialiseOther().
saveRecurseSkippable = (0 == (propertiesOneExportedSave.length + propertiesOneImportedSave.length + propertiesManySave.length));
// Check if there are no cascade delete associated beans (also subject to
// change in initialiseOther()).
deleteRecurseSkippable = (0 == (propertiesOneExportedDelete.length + propertiesOneImportedDelete.length + propertiesManyDelete.length));
// object used to handle Id values
this.idBinder = owner.createIdBinder(idProperty);
this.whenModifiedProperty = findWhenModifiedProperty();
this.whenCreatedProperty = findWhenCreatedProperty();
// derive the index position of the Id and Version properties
this.abstractType = Modifier.isAbstract(beanType.getModifiers());
if (abstractType) {
this.idPropertyIndex = -1;
this.versionPropertyIndex = -1;
this.unloadProperties = new int[0];
this.propertiesIndex = new BeanProperty[0];
} else {
EntityBeanIntercept ebi = prototypeEntityBean._ebean_getIntercept();
this.idPropertyIndex = (idProperty == null) ? -1 : ebi.findProperty(idProperty.name());
this.versionPropertyIndex = (versionProperty == null) ? -1 : ebi.findProperty(versionProperty.name());
this.unloadProperties = derivePropertiesToUnload(prototypeEntityBean);
this.propertiesIndex = new BeanProperty[ebi.propertyLength()];
for (int i = 0; i < propertiesIndex.length; i++) {
propertiesIndex[i] = propMap.get(ebi.property(i));
}
}
}
public String idSelect() {
if (idBinder == null) throw new UnsupportedOperationException();
return idBinder.idSelect();
}
public boolean isJacksonCorePresent() {
return owner.isJacksonCorePresent();
}
private BeanDescriptorJsonHelp initJsonHelp() {
return isJacksonCorePresent() ? new BeanDescriptorJsonHelp<>(this) : null;
}
/**
* Return true if the bean should be treated as a reference bean when it only has its id populated.
* To be true it has other scalar properties that are not generated on insert.
*/
private boolean isIdOnlyReference(BeanProperty[] baseScalar) {
for (BeanProperty beanProperty : baseScalar) {
if (!beanProperty.isGeneratedOnInsert()) {
return true;
}
}
return false;
}
/**
* Derive an array of property positions for properties that are initialised in the constructor.
* These properties need to be unloaded when populating beans for queries.
*/
private int[] derivePropertiesToUnload(EntityBean prototypeEntityBean) {
boolean[] loaded = prototypeEntityBean._ebean_getIntercept().loaded();
int[] props = new int[loaded.length];
int pos = 0;
// collect the positions of the properties initialised in the default constructor.
for (int i = 0; i < loaded.length; i++) {
if (loaded[i]) {
props[pos++] = i;
}
}
if (pos == 0) {
// nothing set in the constructor
return new int[0];
}
// populate a smaller/minimal array
int[] unload = new int[pos];
System.arraycopy(props, 0, unload, 0, pos);
return unload;
}
/**
* Create an entity bean that is used as a prototype/factory to create new instances.
*/
EntityBean createPrototypeEntityBean(Class beanType) {
if (Modifier.isAbstract(beanType.getModifiers())) {
return null;
}
try {
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
}
/**
* Return the DatabaseConfig.
*/
public DatabaseBuilder.Settings config() {
return owner.config();
}
/**
* Set the server. Primarily so that the Many's can lazy load.
*/
public void setEbeanServer(SpiEbeanServer ebeanServer) {
this.ebeanServer = ebeanServer;
for (BeanPropertyAssocMany> assocMany : propertiesMany) {
// used for creating lazy loading lists etc
assocMany.setEbeanServer(ebeanServer);
}
}
/**
* Return the EbeanServer instance that owns this BeanDescriptor.
*/
public SpiEbeanServer ebeanServer() {
return ebeanServer;
}
/**
* Return true if this is an abstract type.
*/
boolean isAbstractType() {
return abstractType;
}
/**
* Return true if this is a "Doc Store only" entity bean.
*/
@Override
public boolean isDocStoreOnly() {
return EntityType.DOC == entityType;
}
/**
* Return the type of this domain object.
*/
public EntityType entityType() {
return entityType;
}
private String[] properties() {
return properties;
}
public BeanProperty propertyByIndex(int pos) {
return propertiesIndex[pos];
}
/**
* Initialise the Id properties first.
*
* These properties need to be initialised prior to the association properties
* as they are used to get the imported and exported properties.
*/
void initialiseId(BeanDescriptorInitContext initContext) {
if (draftable) {
initContext.addDraft(baseTable, draftTable);
}
if (historySupport) {
// add mapping (used to swap out baseTable for asOf queries)
initContext.addHistory(baseTable, baseTableAsOf);
}
if (inheritInfo != null) {
inheritInfo.setDescriptor(this);
}
// initialise just the Id property only
if (idProperty != null) {
idProperty.initialise(initContext);
}
}
/**
* Initialise the exported and imported parts for associated properties.
*/
public void initialiseOther(BeanDescriptorInitContext initContext) {
for (BeanPropertyAssocMany> many : propertiesManyToMany) {
// register associated draft table for M2M intersection
many.registerDraftIntersectionTable(initContext);
}
if (historySupport) {
// history support on this bean so check all associated intersection tables
// and if they are not excluded register the associated 'with history' table
for (BeanPropertyAssocMany> manyToMany : propertiesManyToMany) {
// register associated history table for M2M intersection
if (!manyToMany.isExcludedFromHistory()) {
TableJoin intersectionTableJoin = manyToMany.intersectionTableJoin();
initContext.addHistoryIntersection(intersectionTableJoin.getTable());
}
}
}
// initialise all the non-id properties
for (BeanProperty prop : propertiesAll()) {
if (!prop.isId()) {
prop.initialise(initContext);
}
prop.registerColumn(this, null);
}
if (unidirectional != null) {
unidirectional.initialise(initContext);
}
idBinder.initialise();
idBinderInLHSSql = idBinder.bindInSql(baseTableAlias);
idBinderIdSql = idBinder.bindEqSql(baseTableAlias);
String idBinderInLHSSqlNoAlias = idBinder.bindInSql(null);
String idEqualsSql = idBinder.bindEqSql(null);
deleteByIdSql = "delete from " + baseTable + " where " + idEqualsSql;
whereIdInSql = " where " + idBinderInLHSSqlNoAlias + " ";
deleteByIdInSql = "delete from " + baseTable + whereIdInSql;
if (softDelete) {
softDeleteByIdSql = "update " + baseTable + " set " + softDeleteDbSet() + " where " + idEqualsSql;
softDeleteByIdInSql = "update " + baseTable + " set " + softDeleteDbSet() + " where " + idBinderInLHSSqlNoAlias + " ";
} else {
softDeleteByIdSql = null;
softDeleteByIdInSql = null;
}
initNaturalKey();
}
private void initNaturalKey() {
final String[] naturalKey = cacheHelp.getNaturalKey();
if (naturalKey != null && naturalKey.length != 0) {
BeanProperty[] props = new BeanProperty[naturalKey.length];
for (int i = 0; i < naturalKey.length; i++) {
props[i] = beanProperty(naturalKey[i]);
}
this.beanNaturalKey = new BeanNaturalKey(naturalKey, props);
}
}
private boolean hasCircularImportedId() {
for (BeanPropertyAssocOne> assocOne : propertiesOneImportedSave) {
if (assocOne.hasCircularImportedId(this)) {
return true;
}
}
return false;
}
boolean hasCircularImportedIdTo(BeanDescriptor> sourceDesc) {
for (BeanPropertyAssocOne> assocOne : propertiesOneImportedSave) {
if (assocOne.targetDescriptor() == sourceDesc) {
return true;
}
}
return false;
}
void registerColumn(String dbColumn, String path) {
String key = dbColumn.toLowerCase();
// check for clash with imported OneToOne PK
if (!columnPath.containsKey(key)) {
columnPath.put(key, path);
}
}
void registerTable(String baseTable, BeanPropertyAssoc> assocProperty) {
if (baseTable != null) {
tablePath.put(baseTable.toLowerCase(), assocProperty);
}
}
/**
* Perform last initialisation for the descriptor.
*/
void initLast() {
for (BeanProperty prop : propertiesNonTransient) {
if (prop.isUnique()) {
propertiesUnique.add(new BeanProperty[]{prop});
}
}
// convert unique columns to properties
if (indexDefinitions != null) {
for (IndexDefinition indexDef : indexDefinitions) {
if (indexDef.isUnique()) {
addUniqueColumns(indexDef);
}
}
}
docStoreEmbeddedInvalidation = docStoreAdapter.hasEmbeddedInvalidation();
}
private void addUniqueColumns(IndexDefinition indexDef) {
String[] cols = indexDef.getColumns();
BeanProperty[] props = new BeanProperty[cols.length];
for (int i = 0; i < cols.length; i++) {
String propName = findBeanPath("", "", cols[i]);
if (propName == null) {
return;
}
props[i] = findProperty(propName);
}
if (props.length == 1) {
for (BeanProperty[] inserted : propertiesUnique) {
if (inserted.length == 1 && inserted[0].equals(props[0])) {
return; // do not insert duplicates
}
}
}
propertiesUnique.add(props);
}
/**
* Initialise the document mapping.
*/
@SuppressWarnings("unchecked")
void initialiseDocMapping() {
batchEscalateOnCascadeInsert = supportBatchEscalateOnInsert();
batchEscalateOnCascadeDelete = supportBatchEscalateOnDelete();
for (BeanPropertyAssocMany> many : propertiesMany) {
many.initialisePostTarget();
}
for (BeanPropertyAssocOne> one : propertiesOne) {
one.initialisePostTarget();
}
if (inheritInfo != null && !inheritInfo.isRoot()) {
docStoreAdapter = (DocStoreBeanAdapter) inheritInfo.getRoot().desc().docStoreAdapter();
}
docMapping = docStoreAdapter.createDocMapping();
docStoreAdapter.registerPaths();
cacheHelp.deriveNotifyFlags();
}
private boolean supportBatchEscalateOnDelete() {
if (softDelete) {
return false;
}
for (BeanPropertyAssocMany> assocMany : propertiesManyDelete) {
if (assocMany.isCascadeDeleteEscalate()) {
return true;
}
}
return false;
}
private boolean supportBatchEscalateOnInsert() {
return idType == IdType.IDENTITY || !hasCircularImportedId();
}
/**
* Return false if JDBC batch can't be implicitly escalated to.
* This happens when we have circular import id situation (need to defer setting identity value).
*/
public boolean isBatchEscalateOnCascade(PersistRequest.Type type) {
return type == PersistRequest.Type.INSERT ? batchEscalateOnCascadeInsert : batchEscalateOnCascadeDelete;
}
void initInheritInfo() {
if (inheritInfo != null) {
// need to check every BeanDescriptor in the inheritance hierarchy
if (saveRecurseSkippable) {
saveRecurseSkippable = inheritInfo.isSaveRecurseSkippable();
}
if (deleteRecurseSkippable) {
deleteRecurseSkippable = inheritInfo.isDeleteRecurseSkippable();
}
}
}
public void metricPersistBatch(PersistRequest.Type type, long startNanos, int size) {
iudMetrics.addBatch(type, startNanos, size);
}
public void metricPersistNoBatch(PersistRequest.Type type, long startNanos) {
iudMetrics.addNoBatch(type, startNanos);
}
public void merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
EntityBeanIntercept toEbi = existing._ebean_getIntercept();
int propertyLength = toEbi.propertyLength();
String[] names = properties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i)) {
BeanProperty property = beanProperty(names[i]);
if (!toEbi.isLoadedProperty(i)) {
Object val = property.getValue(bean);
property.setValue(existing, val);
} else if (property.isMany()) {
property.merge(bean, existing);
}
}
}
}
/**
* Bind all the property values to the SqlUpdate.
*/
public void bindElementValue(SqlUpdate insert, Object value) {
EntityBean bean = (EntityBean) value;
for (BeanProperty property : propertiesBaseScalar) {
insert.setParameter(property.getValue(bean));
}
}
/**
* Return the ReadAuditLogger for logging read audit events.
*/
public ReadAuditLogger readAuditLogger() {
return ebeanServer.readAuditLogger();
}
/**
* Return the ReadAuditPrepare for preparing read audit events prior to logging.
*/
private ReadAuditPrepare readAuditPrepare() {
return ebeanServer.readAuditPrepare();
}
public boolean isChangeLog() {
return changeLogFilter != null;
}
/**
* Return true if this request should be included in the change log.
*/
public BeanChange changeLogBean(PersistRequestBean request) {
switch (request.type()) {
case INSERT:
return changeLogFilter.includeInsert(request) ? insertBeanChange(request) : null;
case UPDATE:
case DELETE_SOFT:
return changeLogFilter.includeUpdate(request) ? updateBeanChange(request) : null;
case DELETE:
return changeLogFilter.includeDelete(request) ? deleteBeanChange(request) : null;
default:
throw new IllegalStateException("Unhandled request type " + request.type());
}
}
private BeanChange beanChange(ChangeType type, Object id, String data, String oldData) {
Object tenantId = ebeanServer.currentTenantId();
return new BeanChange(name, tenantId, id, type, data, oldData);
}
/**
* Return the bean change for a delete.
*/
private BeanChange deleteBeanChange(PersistRequestBean request) {
return beanChange(ChangeType.DELETE, request.beanId(), null, null);
}
/**
* Return the bean change for an update generating 'new values' and 'old values' in JSON form.
*/
private BeanChange updateBeanChange(PersistRequestBean request) {
try {
BeanChangeJson changeJson = new BeanChangeJson(this, request.isStatelessUpdate());
request.intercept().addDirtyPropertyValues(changeJson);
changeJson.flush();
return beanChange(ChangeType.UPDATE, request.beanId(), changeJson.newJson(), changeJson.oldJson());
} catch (RuntimeException e) {
log.log(ERROR, "Failed to write ChangeLog entry for update", e);
return null;
}
}
/**
* Return the bean change for an insert.
*/
private BeanChange insertBeanChange(PersistRequestBean request) {
try {
StringWriter writer = new StringWriter(200);
SpiJsonWriter jsonWriter = createJsonWriter(writer);
jsonWriteForInsert(jsonWriter, request.entityBean());
jsonWriter.flush();
return beanChange(ChangeType.INSERT, request.beanId(), writer.toString(), null);
} catch (IOException e) {
log.log(ERROR, "Failed to write ChangeLog entry for insert", e);
return null;
}
}
SpiJsonWriter createJsonWriter(StringWriter writer) {
return ebeanServer.jsonExtended().createJsonWriter(writer);
}
SpiJsonReader createJsonReader(String json) {
return ebeanServer.jsonExtended().createJsonRead(this, json);
}
/**
* Populate the diff for inserts with flattened non-null property values.
*/
void jsonWriteForInsert(SpiJsonWriter jsonWriter, EntityBean newBean) throws IOException {
jsonWriter.writeStartObject();
for (BeanProperty prop : propertiesBaseScalar) {
prop.jsonWriteForInsert(jsonWriter, newBean);
}
for (BeanPropertyAssocOne> prop : propertiesOne) {
prop.jsonWriteForInsert(jsonWriter, newBean);
}
for (BeanPropertyAssocOne> prop : propertiesEmbedded) {
prop.jsonWriteForInsert(jsonWriter, newBean);
}
jsonWriter.writeEndObject();
}
public SqlUpdate deleteById(Object id, List