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.PersistenceContextScope;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.SqlUpdate;
import io.ebean.Transaction;
import io.ebean.ValuePair;
import io.ebean.annotation.DocStoreMode;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.cache.QueryCacheEntry;
import io.ebean.config.EncryptKey;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanPostConstructListener;
import io.ebean.event.BeanPostLoad;
import io.ebean.event.BeanQueryAdapter;
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.MetricVisitor;
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.BeanCacheResult;
import io.ebeaninternal.api.CQueryPlanKey;
import io.ebeaninternal.api.ConcurrencyMode;
import io.ebeaninternal.api.LoadContext;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiUpdatePlan;
import io.ebeaninternal.api.TransactionEventTable.TableIUD;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.cache.CacheChangeSet;
import io.ebeaninternal.server.cache.CachedBeanData;
import io.ebeaninternal.server.cache.CachedManyIds;
import io.ebeaninternal.server.core.CacheOptions;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.core.PersistRequest;
import io.ebeaninternal.server.core.PersistRequestBean;
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.ElComparator;
import io.ebeaninternal.server.el.ElComparatorCompound;
import io.ebeaninternal.server.el.ElComparatorProperty;
import io.ebeaninternal.server.el.ElPropertyChainBuilder;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.persist.DeleteMode;
import io.ebeaninternal.server.persist.DmlUtil;
import io.ebeaninternal.server.query.CQueryPlan;
import io.ebeaninternal.server.query.ExtraJoin;
import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.STreePropertyAssoc;
import io.ebeaninternal.server.query.STreePropertyAssocMany;
import io.ebeaninternal.server.query.STreePropertyAssocOne;
import io.ebeaninternal.server.query.STreeType;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.ScalarType;
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.DocPropertyType;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Describes Beans including their deployment information.
*/
public class BeanDescriptor implements BeanType, STreeType {
private static final Logger logger = LoggerFactory.getLogger(BeanDescriptor.class);
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 Map namedRawSql;
private final Map namedQuery;
private final short profileBeanId;
private final ProfileLocation locationById;
private final ProfileLocation locationAll;
private final boolean multiValueSupported;
public enum EntityType {
ORM, EMBEDDED, VIEW, SQL, DOC
}
/**
* The EbeanServer name. Same as the plugin name.
*/
private final String serverName;
/**
* The nature/type of this bean.
*/
private final EntityType entityType;
/**
* Type of Identity generation strategy used.
*/
private final IdType idType;
/**
* Set when Id property is marked with GeneratedValue annotation.
*/
private final boolean idGeneratedValue;
private final boolean idTypePlatformDefault;
private final PlatformIdGenerator idGenerator;
/**
* The database sequence name (optional).
*/
private final String sequenceName;
private final int sequenceInitialValue;
private final int sequenceAllocationSize;
/**
* SQL used to return last inserted id. Used for Identity columns where
* getGeneratedKeys is not supported.
*/
private final String selectLastInsertedId;
private final boolean autoTunable;
/**
* The concurrency mode for beans of this type.
*/
private final ConcurrencyMode concurrencyMode;
private final IndexDefinition[] indexDefinitions;
private final String[] dependentTables;
/**
* The base database table.
*/
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;
/**
* DB table comment.
*/
private final String dbComment;
/**
* Set to true if read auditing is on for this bean type.
*/
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;
/**
* Map of BeanProperty Linked so as to preserve order.
*/
protected 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<>();
/**
* The type of bean this describes.
*/
final Class beanType;
protected final Class> rootBeanType;
/**
* This is not sent to a remote client.
*/
private final BeanDescriptorMap owner;
final String[] properties;
/**
* Intercept pre post on insert,update, and delete .
*/
private volatile BeanPersistController persistController;
private final BeanPostLoad beanPostLoad;
private final BeanPostConstructListener beanPostConstructListener;
/**
* Listens for post commit insert update and delete events.
*/
private volatile BeanPersistListener persistListener;
private final BeanQueryAdapter queryAdapter;
/**
* If set overrides the find implementation. Server side only.
*/
private final BeanFindController beanFinder;
/**
* Used for fine grain filtering for the change log.
*/
private final ChangeLogFilter changeLogFilter;
/**
* The table joins for this bean.
*/
private final TableJoin[] derivedTableJoins;
/**
* Inheritance information. Server side only.
*/
protected final InheritInfo inheritInfo;
private final boolean abstractType;
/**
* Derived list of properties that make up the unique id.
*/
protected final BeanProperty idProperty;
private final int idPropertyIndex;
/**
* Derived list of properties that are used for version concurrency checking.
*/
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;
/**
* list of properties that are Lists/Sets/Maps (Derived).
*/
private final BeanProperty[] propertiesNonMany;
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>[] propertiesOneExported;
private final BeanPropertyAssocOne>[] propertiesOneExportedSave;
private final BeanPropertyAssocOne>[] propertiesOneExportedDelete;
/**
* list of properties that are embedded beans.
*/
private final BeanPropertyAssocOne>[] propertiesEmbedded;
/**
* List of the scalar properties excluding id and secondary table properties.
*/
private final BeanProperty[] propertiesBaseScalar;
private final BeanProperty[] propertiesTransient;
/**
* All non transient properties excluding the id properties.
*/
private final BeanProperty[] propertiesNonTransient;
protected final BeanProperty[] propertiesIndex;
private final BeanProperty[] propertiesGenInsert;
private final BeanProperty[] propertiesGenUpdate;
private final List propertiesUnique = new ArrayList<>();
/**
* The bean class name or the table name for MapBeans.
*/
private final String fullName;
/**
* Flag used to determine if saves can be skipped.
*/
private boolean saveRecurseSkippable;
/**
* Flag used to determine if deletes can be skipped.
*/
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;
/**
* If true then only changed properties get updated.
*/
private final boolean updateChangesOnly;
private final boolean cacheSharableBeans;
private final String docStoreQueueId;
private final BeanDescriptorDraftHelp draftHelp;
private final BeanDescriptorCacheHelp cacheHelp;
final BeanDescriptorJsonHelp jsonHelp;
private DocStoreBeanAdapter docStoreAdapter;
private DocumentMapping docMapping;
private boolean docStoreEmbeddedInvalidation;
private final String defaultSelectClause;
private SpiEbeanServer ebeanServer;
/**
* Construct the BeanDescriptor.
*/
public BeanDescriptor(BeanDescriptorMap owner, DeployBeanDescriptor deploy) {
this.owner = owner;
this.multiValueSupported = owner.isMultiValueSupported();
this.serverName = owner.getServerName();
this.entityType = deploy.getEntityType();
this.properties = deploy.getProperties();
this.name = InternString.intern(deploy.getName());
this.baseTableAlias = "t0";
this.fullName = InternString.intern(deploy.getFullName());
this.locationById = ProfileLocation.createAt(fullName + ".byId");
this.locationAll = ProfileLocation.createAt(fullName + ".all");
this.profileBeanId = deploy.getProfileId();
this.beanType = deploy.getBeanType();
this.rootBeanType = PersistenceContextUtil.root(beanType);
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
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.idType = deploy.getIdType();
this.idGeneratedValue = deploy.isIdGeneratedValue();
this.idTypePlatformDefault = deploy.isIdTypePlatformDefault();
this.idGenerator = deploy.getIdGenerator();
this.sequenceName = deploy.getSequenceName();
this.sequenceInitialValue = deploy.getSequenceInitialValue();
this.sequenceAllocationSize = deploy.getSequenceAllocationSize();
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
this.concurrencyMode = deploy.getConcurrencyMode();
this.updateChangesOnly = deploy.isUpdateChangesOnly();
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.autoTunable = EntityType.ORM == entityType && (beanFinder == null);
// helper object used to derive lists of properties
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
this.softDelete = (softDeleteProperty != null);
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.propertiesManySave = listHelper.getManySave();
this.propertiesManyDelete = listHelper.getManyDelete();
this.propertiesManyToMany = listHelper.getManyToMany();
this.propertiesGenInsert = listHelper.getGeneratedInsert();
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
this.derivedTableJoins = listHelper.getTableJoin();
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = new BeanDescriptorJsonHelp<>(this);
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
this.docStoreQueueId = docStoreAdapter.getQueueId();
// 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.getName());
this.versionPropertyIndex = (versionProperty == null) ? -1 : ebi.findProperty(versionProperty.getName());
this.unloadProperties = derivePropertiesToUnload(prototypeEntityBean);
this.propertiesIndex = new BeanProperty[ebi.getPropertyLength()];
for (int i = 0; i < propertiesIndex.length; i++) {
propertiesIndex[i] = propMap.get(ebi.getProperty(i));
}
}
}
/**
* Return a location for "find by id".
*/
public ProfileLocation profileLocationById() {
return locationById;
}
/**
* Return a location for "find all".
*/
public ProfileLocation profileLocationAll() {
return locationAll;
}
/**
* Return the id used in profiling to identify the bean type.
*/
@Override
public short getProfileId() {
return profileBeanId;
}
/**
* 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().getLoaded();
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.
*/
protected EntityBean createPrototypeEntityBean(Class beanType) {
if (Modifier.isAbstract(beanType.getModifiers())) {
return null;
}
try {
return (EntityBean) beanType.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
}
/**
* Return the ServerConfig.
*/
public ServerConfig getServerConfig() {
return owner.getServerConfig();
}
/**
* 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 getEbeanServer() {
return ebeanServer;
}
/**
* Return true if this is an abstract type.
*/
public 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 getEntityType() {
return entityType;
}
public String[] getProperties() {
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.
*
*/
public void initialiseId(BeanDescriptorInitContext initContext) {
if (logger.isTraceEnabled()) {
logger.trace("BeanDescriptor initialise " + fullName);
}
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);
}
if (isEmbedded()) {
// initialise all the properties
for (BeanProperty prop : propertiesAll()) {
prop.initialise(initContext);
}
} else {
// initialise just the Id properties
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> aPropertiesManyToMany : propertiesManyToMany) {
// register associated history table for M2M intersection
if (!aPropertiesManyToMany.isExcludedFromHistory()) {
TableJoin intersectionTableJoin = aPropertiesManyToMany.getIntersectionTableJoin();
initContext.addHistoryIntersection(intersectionTableJoin.getTable());
}
}
}
if (!isEmbedded()) {
// 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.getBindIdInSql(baseTableAlias);
idBinderIdSql = idBinder.getBindIdSql(baseTableAlias);
String idBinderInLHSSqlNoAlias = idBinder.getBindIdInSql(null);
String idEqualsSql = idBinder.getBindIdSql(null);
deleteByIdSql = "delete from " + baseTable + " where " + idEqualsSql;
whereIdInSql = " where " + idBinderInLHSSqlNoAlias + " ";
deleteByIdInSql = "delete from " + baseTable + whereIdInSql;
if (softDelete) {
softDeleteByIdSql = "update " + baseTable + " set " + getSoftDeleteDbSet() + " where " + idEqualsSql;
softDeleteByIdInSql = "update " + baseTable + " set " + getSoftDeleteDbSet() + " where " + idBinderInLHSSqlNoAlias + " ";
} else {
softDeleteByIdSql = null;
softDeleteByIdInSql = null;
}
}
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.
*/
public 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")
public void initialiseDocMapping() {
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();
}
public 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 merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
EntityBeanIntercept toEbi = existing._ebean_getIntercept();
int propertyLength = toEbi.getPropertyLength();
String[] names = getProperties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i)) {
BeanProperty property = getBeanProperty(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.setNextParameter(property.getValue(bean));
}
}
/**
* Return the ReadAuditLogger for logging read audit events.
*/
public ReadAuditLogger getReadAuditLogger() {
return ebeanServer.getReadAuditLogger();
}
/**
* Return the ReadAuditPrepare for preparing read audit events prior to logging.
*/
public ReadAuditPrepare getReadAuditPrepare() {
return ebeanServer.getReadAuditPrepare();
}
public boolean isChangeLog() {
return changeLogFilter != null;
}
/**
* Return true if this request should be included in the change log.
*/
public BeanChange getChangeLogBean(PersistRequestBean request) {
switch (request.getType()) {
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.getType());
}
}
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.getBeanId(), 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.getEntityBeanIntercept().addDirtyPropertyValues(changeJson);
changeJson.flush();
return beanChange(ChangeType.UPDATE, request.getBeanId(), changeJson.newJson(), changeJson.oldJson());
} catch (RuntimeException e) {
logger.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.getEntityBean());
jsonWriter.flush();
return beanChange(ChangeType.INSERT, request.getBeanId(), writer.toString(), null);
} catch (IOException e) {
logger.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.
*/
protected 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