#919 - io.ebean package initial

This commit is contained in:
Rob Bygrave committed 2016-12-11 23:23:22 +13:00
1 parent 5821dc96b9
commit 971e2dc91b
2134 files changed
+10721 -8652

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,35 @@
package io.ebeaninternal.server.deploy.meta;
import java.util.HashMap;
import java.util.Map;
/**
* Collects Deployment information on Embedded beans.
* <p>
* Typically collects the overridden column names mapped
* to the Embedded bean.
* </p>
*/
public class DeployBeanEmbedded {
/**
* A map of property names to dbColumns.
*/
private final Map<String, String> propMap = new HashMap<>();
/**
* Set a Map of property names to dbColumns.
*/
public void putAll(Map<String, String> propertyColumnMap) {
propMap.putAll(propertyColumnMap);
}
/**
* Return a map of property names to dbColumns.
*/
public Map<String, String> getPropertyColumnMap() {
return propMap;
}
}
@@ -0,0 +1,992 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.annotation.CreatedTimestamp;
import io.ebean.annotation.DocCode;
import io.ebean.annotation.DocProperty;
import io.ebean.annotation.DocSortable;
import io.ebean.annotation.SoftDelete;
import io.ebean.annotation.UpdatedTimestamp;
import io.ebean.annotation.WhenCreated;
import io.ebean.annotation.WhenModified;
import io.ebean.annotation.WhoCreated;
import io.ebean.annotation.WhoModified;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DeployDocPropertyOptions;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
import io.ebeaninternal.server.deploy.parse.AnnotationBase;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.properties.BeanPropertyGetter;
import io.ebeaninternal.server.properties.BeanPropertySetter;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeWrapper;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import javax.persistence.EmbeddedId;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Version;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.Types;
/**
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
*/
public class DeployBeanProperty {
private static final int ID_ORDER = 1000000;
private static final int UNIDIRECTIONAL_ORDER = 100000;
private static final int AUDITCOLUMN_ORDER = -1000000;
private static final int VERSIONCOLUMN_ORDER = -1000000;
/**
* Flag to mark this at part of the unique id.
*/
private boolean id;
/**
* Flag to mark the property as embedded. This could be on
* BeanPropertyAssocOne rather than here. Put it here for checking Id type
* (embedded or not).
*/
private boolean embedded;
/**
* Flag indicating if this the version property.
*/
private boolean versionColumn;
private boolean fetchEager = true;
/**
* Set if this property is nullable.
*/
private boolean nullable = true;
private boolean unique;
private boolean discriminator;
/**
* The length or precision of the DB column.
*/
private int dbLength;
private int dbScale;
private String dbColumnDefn;
private boolean isTransient;
private boolean localEncrypted;
private boolean jsonSerialize = true;
private boolean jsonDeserialize = true;
private boolean dbEncrypted;
private DbEncryptFunction dbEncryptFunction;
private int dbEncryptedType;
private String dbBind = "?";
/**
* Is this property include in database resultSet.
*/
private boolean dbRead;
/**
* Include this in DB insert.
*/
private boolean dbInsertable;
/**
* Include this in a DB update.
*/
private boolean dbUpdateable;
private DeployTableJoin secondaryTableJoin;
private String secondaryTableJoinPrefix;
/**
* Set to true if this property is based on a secondary table.
*/
private String secondaryTable;
/**
* The type that owns this property.
*/
private Class<?> owningType;
/**
* True if the property is a Clob, Blob LongVarchar or LongVarbinary.
*/
private boolean lob;
private boolean naturalKey;
/**
* The logical bean property name.
*/
private String name;
/**
* The reflected field.
*/
private Field field;
/**
* The bean type.
*/
private final Class<?> propertyType;
private final Type genericType;
/**
* Set for Non-JDBC types to provide logical to db type conversion.
*/
private ScalarType<?> scalarType;
/**
* The database column. This can include quoted identifiers.
*/
private String dbColumn;
private String aggregationPrefix;
private String aggregation;
private String sqlFormulaSelect;
private String sqlFormulaJoin;
/**
* The jdbc data type this maps to.
*/
private int dbType;
private DeployDocPropertyOptions docMapping = new DeployDocPropertyOptions();
/**
* The method used to read the property.
*/
private Method readMethod;
private int propertyIndex;
private BeanPropertyGetter getter;
private BeanPropertySetter setter;
/**
* Generator for insert or update timestamp etc.
*/
private GeneratedProperty generatedProperty;
protected final DeployBeanDescriptor<?> desc;
private boolean undirectionalShadow;
private int sortOrder;
private boolean excludedFromHistory;
private boolean tenantId;
private boolean draft;
private boolean draftOnly;
private boolean draftDirty;
private boolean draftReset;
private boolean softDelete;
private boolean unmappedJson;
private String dbComment;
private String dbColumnDefault;
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
this.desc = desc;
this.propertyType = propertyType;
this.genericType = null;
this.scalarType = wrapScalarType(propertyType, scalarType, typeConverter);
this.dbType = (scalarType == null) ? 0 : scalarType.getJdbcType();
}
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, Type genericType) {
this.desc = desc;
this.propertyType = propertyType;
this.genericType = genericType;
}
/**
* Wrap the ScalarType using a ScalarTypeConverter.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private ScalarType<?> wrapScalarType(Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
if (typeConverter == null) {
return scalarType;
}
return new ScalarTypeWrapper(propertyType, scalarType, typeConverter);
}
public int getSortOverride() {
if (field == null) {
return 0;
}
if (AnnotationBase.findAnnotation(field, Id.class) != null) {
return ID_ORDER;
} else if (AnnotationBase.findAnnotation(field, EmbeddedId.class) != null) {
return ID_ORDER;
} else if (undirectionalShadow) {
return UNIDIRECTIONAL_ORDER;
} else if (isAuditProperty()) {
return AUDITCOLUMN_ORDER;
} else if (AnnotationBase.findAnnotation(field, Version.class) != null) {
return VERSIONCOLUMN_ORDER;
} else if (AnnotationBase.findAnnotation(field, SoftDelete.class) != null) {
return VERSIONCOLUMN_ORDER;
}
return 0;
}
private boolean isAuditProperty() {
return (AnnotationBase.findAnnotation(field, WhenCreated.class) != null
|| AnnotationBase.findAnnotation(field, WhenModified.class) != null
|| AnnotationBase.findAnnotation(field, WhoModified.class) != null
|| AnnotationBase.findAnnotation(field, WhoCreated.class) != null
|| AnnotationBase.findAnnotation(field, UpdatedTimestamp.class) != null
|| AnnotationBase.findAnnotation(field, CreatedTimestamp.class) != null);
}
public String getFullBeanName() {
return desc.getFullName() + "." + name;
}
/**
* Return the DB column length for character columns.
* <p>
* Note if there is no length explicitly defined then the scalarType is
* checked to see if that has one (primarily to support putting a length on
* Enum types).
* </p>
*/
public int getDbLength() {
if (dbLength == 0 && scalarType != null) {
return scalarType.getLength();
}
return dbLength;
}
public boolean isJsonSerialize() {
return jsonSerialize;
}
public void setJsonSerialize(boolean jsonSerialize) {
this.jsonSerialize = jsonSerialize;
}
public boolean isJsonDeserialize() {
return jsonDeserialize;
}
public void setJsonDeserialize(boolean jsonDeserialize) {
this.jsonDeserialize = jsonDeserialize;
}
/**
* Return the sortOrder for the properties.
*/
public int getSortOrder() {
return sortOrder;
}
/**
* Set the sortOrder for the properties.
*/
public void setSortOrder(int sortOrder) {
this.sortOrder = sortOrder;
}
/**
* Return true if this is a placeholder property for a unidirectional relationship.
*/
public boolean isUndirectionalShadow() {
return undirectionalShadow;
}
/**
* Mark this property as a placeholder for a unidirectional relationship.
*/
public void setUndirectionalShadow() {
this.undirectionalShadow = true;
}
/**
* Mark this property as mapping to the discriminator column.
*/
public void setDiscriminator() {
this.discriminator = true;
}
/**
* Return true if this property maps to the inheritance discriminator column.s
*/
public boolean isDiscriminator() {
return discriminator;
}
/**
* Return true if the property is encrypted in java rather than in the DB.
*/
public boolean isLocalEncrypted() {
return localEncrypted;
}
/**
* Set to true when the property is encrypted in java rather than in the DB.
*/
public void setLocalEncrypted() {
this.localEncrypted = true;
}
/**
* Set the DB column length for character columns.
*/
public void setDbLength(int dbLength) {
this.dbLength = dbLength;
}
/**
* Return the Db scale for numeric columns.
*/
public int getDbScale() {
return dbScale;
}
/**
* Set the Db scale for numeric columns.
*/
public void setDbScale(int dbScale) {
this.dbScale = dbScale;
}
/**
* Return the DB column definition if defined.
*/
public String getDbColumnDefn() {
return dbColumnDefn;
}
/**
* Set a specific DB column definition.
*/
public void setDbColumnDefn(String dbColumnDefn) {
if (dbColumnDefn == null || dbColumnDefn.trim().isEmpty()) {
this.dbColumnDefn = null;
} else {
this.dbColumnDefn = InternString.intern(dbColumnDefn);
}
}
/**
* Return the scalarType. This returns null for native JDBC types, otherwise
* it is used to convert between logical types and jdbc types.
*/
public ScalarType<?> getScalarType() {
return scalarType;
}
public void setScalarType(ScalarType<?> scalarType) {
this.scalarType = scalarType;
}
public int getPropertyIndex() {
return propertyIndex;
}
public void setPropertyIndex(int propertyIndex) {
this.propertyIndex = propertyIndex;
}
public BeanPropertyGetter getGetter() {
return getter;
}
public BeanPropertySetter getSetter() {
return setter;
}
/**
* Return the getter method.
*/
public Method getReadMethod() {
return readMethod;
}
/**
* Set to the owning type form a Inheritance heirarchy.
*/
public void setOwningType(Class<?> owningType) {
this.owningType = owningType;
}
public Class<?> getOwningType() {
return owningType;
}
/**
* Return true if this is local to this type - aka not from a super type.
*/
public boolean isLocal() {
return owningType == null || owningType.equals(desc.getBeanType());
}
/**
* Set the getter used to read the property value from a bean.
*/
public void setGetter(BeanPropertyGetter getter) {
this.getter = getter;
}
/**
* Set the setter used to set the property value to a bean.
*/
public void setSetter(BeanPropertySetter setter) {
this.setter = setter;
}
/**
* Return the name of the property.
*/
public String getName() {
return name;
}
/**
* Set the name of the property.
*/
public void setName(String name) {
this.name = InternString.intern(name);
}
/**
* Return the bean Field associated with this property.
*/
public Field getField() {
return field;
}
/**
* Set the bean Field associated with this property.
*/
public void setField(Field field) {
this.field = field;
}
public boolean isNaturalKey() {
return naturalKey;
}
public void setNaturalKey() {
this.naturalKey = true;
}
/**
* Return the GeneratedValue. Used to generate update timestamp etc.
*/
public GeneratedProperty getGeneratedProperty() {
return generatedProperty;
}
/**
* Set the GeneratedValue. Used to generate update timestamp etc.
*/
public void setGeneratedProperty(GeneratedProperty generatedValue) {
this.generatedProperty = generatedValue;
}
/**
* Return true if this property is mandatory.
*/
public boolean isNullable() {
return nullable;
}
/**
* Set the not nullable of this property.
*/
public void setNullable(boolean isNullable) {
this.nullable = isNullable;
}
/**
* Return true if the DB column is unique.
*/
public boolean isUnique() {
return unique;
}
/**
* Set to true if the DB column is unique.
*/
public void setUnique(boolean unique) {
this.unique = unique;
}
/**
* Return true if this is a version column used for concurrency checking.
*/
public boolean isVersionColumn() {
return versionColumn;
}
/**
* Set if this is a version column used for concurrency checking.
*/
public void setVersionColumn() {
this.versionColumn = true;
}
/**
* Return true if this should be eager fetched by default.
*/
public boolean isFetchEager() {
return fetchEager;
}
/**
* Set the default fetch type for this property.
*/
public void setFetchType(FetchType fetchType) {
this.fetchEager = FetchType.EAGER.equals(fetchType);
}
/**
* Return the formula this property is based on.
*/
public String getSqlFormulaSelect() {
return sqlFormulaSelect;
}
public String getSqlFormulaJoin() {
return sqlFormulaJoin;
}
/**
* The property is based on a formula.
*/
public void setSqlFormula(String formulaSelect, String formulaJoin) {
this.sqlFormulaSelect = formulaSelect;
this.sqlFormulaJoin = formulaJoin.equals("") ? null : formulaJoin;
this.dbRead = true;
this.dbInsertable = false;
this.dbUpdateable = false;
}
public boolean isAggregation() {
return aggregation != null;
}
public String getAggregation() {
return aggregation;
}
public void setAggregation(String aggregation) {
this.aggregation = aggregation;
this.dbRead = true;
this.dbInsertable = false;
this.dbUpdateable = false;
}
/**
* Set the path to the aggregation.
*/
public void setAggregationPrefix(String aggregationPrefix) {
this.aggregationPrefix = aggregationPrefix;
this.aggregation = aggregation.replace(aggregationPrefix, "u1");
}
public String getElPrefix() {
if (aggregation != null) {
return aggregationPrefix;
} else {
return secondaryTableJoinPrefix;
}
}
public String getElPlaceHolder() {
if (aggregation != null) {
return aggregation;
} else if (sqlFormulaSelect != null) {
return sqlFormulaSelect;
} else {
if (secondaryTableJoinPrefix != null) {
return "${" + secondaryTableJoinPrefix + "}" + getDbColumn();
}
// prepend table alias placeholder
return ElPropertyValue.ROOT_ELPREFIX + getDbColumn();
}
}
/**
* The database column name this is mapped to.
*/
public String getDbColumn() {
if (sqlFormulaSelect != null) {
return sqlFormulaSelect;
}
if (aggregation != null) {
return aggregation;
}
return dbColumn;
}
/**
* Set the database column name this is mapped to.
*/
public void setDbColumn(String dbColumn) {
this.dbColumn = InternString.intern(dbColumn);
}
/**
* Return the database jdbc data type this is mapped to.
*/
public int getDbType() {
return dbType;
}
/**
* Set the database jdbc data type this is mapped to.
*/
public void setDbType(int dbType) {
this.dbType = dbType;
this.lob = BeanProperty.isLobType(dbType);
}
/**
* Return true if this is mapped to a Clob Blob LongVarchar or
* LongVarbinary.
*/
public boolean isLob() {
return lob;
}
public boolean isDbNumberType() {
return isNumericType(dbType);
}
private boolean isNumericType(int type) {
switch (type) {
case Types.BIGINT:
return true;
case Types.DECIMAL:
return true;
case Types.DOUBLE:
return true;
case Types.FLOAT:
return true;
case Types.INTEGER:
return true;
case Types.NUMERIC:
return true;
case Types.REAL:
return true;
case Types.SMALLINT:
return true;
case Types.TINYINT:
return true;
default:
return false;
}
}
/**
* Return true if this property is based on a secondary table.
*/
public boolean isSecondaryTable() {
return secondaryTable != null;
}
/**
* Return the secondary table this property is associated with.
*/
public String getSecondaryTable() {
return secondaryTable;
}
/**
* Set to true if this property is included in persisting.
*/
public void setSecondaryTable(String secondaryTable) {
this.secondaryTable = secondaryTable;
this.dbInsertable = false;
this.dbUpdateable = false;
}
/**
*
*/
public String getSecondaryTableJoinPrefix() {
return secondaryTableJoinPrefix;
}
public DeployTableJoin getSecondaryTableJoin() {
return secondaryTableJoin;
}
public void setSecondaryTableJoin(DeployTableJoin secondaryTableJoin, String prefix) {
this.secondaryTableJoin = secondaryTableJoin;
this.secondaryTableJoinPrefix = prefix;
}
/**
* Return the DB Bind parameter. Typically is "?" but can be different for
* encrypted bind.
*/
public String getDbBind() {
return dbBind;
}
/**
* Return true if this property is encrypted in the DB.
*/
public boolean isDbEncrypted() {
return dbEncrypted;
}
public DbEncryptFunction getDbEncryptFunction() {
return dbEncryptFunction;
}
public void setDbEncryptFunction(DbEncryptFunction dbEncryptFunction, DbEncrypt dbEncrypt, int dbLen) {
this.dbEncryptFunction = dbEncryptFunction;
this.dbEncrypted = true;
this.dbBind = dbEncryptFunction.getEncryptBindSql();
this.dbEncryptedType = isLob() ? Types.BLOB : dbEncrypt.getEncryptDbType();
if (dbLen > 0) {
setDbLength(dbLen);
}
}
/**
* Return the DB type for the encrypted property. This can differ from the
* logical type (String encrypted and stored in a VARBINARY)
*/
public int getDbEncryptedType() {
return dbEncryptedType;
}
/**
* Return true if this property is included in database queries.
*/
public boolean isDbRead() {
return dbRead;
}
/**
* Set to true if this property is included in database queries.
*/
public void setDbRead(boolean isDBRead) {
this.dbRead = isDBRead;
}
public boolean isDbInsertable() {
return dbInsertable;
}
public void setDbInsertable(boolean insertable) {
this.dbInsertable = insertable;
}
public boolean isDbUpdateable() {
return dbUpdateable;
}
public void setDbUpdateable(boolean updateable) {
this.dbUpdateable = updateable;
}
/**
* Return true if the property is transient.
*/
public boolean isTransient() {
return isTransient;
}
/**
* Mark the property explicitly as a transient property.
*/
public void setTransient() {
this.isTransient = true;
}
/**
* Set the bean read method.
* <p>
* NB: That a BeanReflectGetter is used to actually perform the getting of
* property values from a bean. This is due to performance considerations.
* </p>
*/
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
/**
* Return the property type.
*/
public Class<?> getPropertyType() {
return propertyType;
}
/**
* Return the generic type for this property.
*/
public Type getGenericType() {
return genericType;
}
/**
* Return true if this is included in the unique id.
*/
public boolean isId() {
return id;
}
/**
* Set to true if this is included in the unique id.
*/
public void setId() {
this.id = true;
}
/**
* Return true if this is an Embedded property. In this case it shares the
* table and pk of its owner object.
*/
public boolean isEmbedded() {
return embedded;
}
/**
* Set to true if this is an embedded property.
*/
public void setEmbedded() {
this.embedded = true;
}
public String toString() {
return desc.getFullName() + "." + name;
}
public boolean isExcludedFromHistory() {
return excludedFromHistory;
}
public void setExcludedFromHistory() {
this.excludedFromHistory = true;
}
public void setDraft() {
this.draft = true;
this.isTransient = true;
}
public boolean isDraft() {
return draft;
}
public void setDraftOnly() {
this.draftOnly = true;
}
public boolean isDraftOnly() {
return draftOnly;
}
public void setDraftDirty() {
this.draftOnly = true;
this.draftDirty = true;
this.nullable = false;
}
public boolean isDraftDirty() {
return draftDirty;
}
public void setDraftReset() {
this.draftReset = true;
}
public boolean isDraftReset() {
return draftReset;
}
public void setSoftDelete() {
this.softDelete = true;
this.nullable = false;
this.dbColumnDefault = DbDefaultValue.FALSE;
}
public boolean isSoftDelete() {
return softDelete;
}
public void setUnmappedJson() {
this.unmappedJson = true;
this.isTransient = true;
}
public boolean isUnmappedJson() {
return unmappedJson;
}
public void setDbComment(String dbComment) {
this.dbComment = dbComment;
}
public String getDbComment() {
return dbComment;
}
public void setDocProperty(DocProperty docProperty) {
docMapping.setDocProperty(docProperty);
}
public void setDocSortable(DocSortable docSortable) {
docMapping.setDocSortable(docSortable);
}
public void setDocCode(DocCode docCode) {
docMapping.setDocCode(docCode);
}
public DocPropertyOptions getDocPropertyOptions() {
return docMapping.create();
}
public String getDbColumnDefault() {
return dbColumnDefault;
}
public void setTenantId() {
this.tenantId = true;
this.nullable = false;
this.dbInsertable = true;
this.dbUpdateable = false;
}
public boolean isTenantId() {
return tenantId;
}
}
@@ -0,0 +1,150 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebeaninternal.server.deploy.BeanCascadeInfo;
import io.ebeaninternal.server.deploy.BeanTable;
/**
* Abstract base for properties mapped to an associated bean, list, set or map.
*/
public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
/**
* The type of the joined bean.
*/
protected Class<T> targetType;
/**
* Persist settings.
*/
private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
/**
* The join table information.
*/
private BeanTable beanTable;
/**
* Join between the beans.
*/
protected final DeployTableJoin tableJoin = new DeployTableJoin();
/**
* Literal added to where clause of lazy loading query.
*/
private String extraWhere;
/**
* From the deployment mappedBy attribute.
*/
private String mappedBy;
private String docStoreDoc;
/**
* Construct the property.
*/
DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
super(desc, targetType, null, null);
this.targetType = targetType;
}
/**
* Return the target DeployBeanDescriptor for this associated bean property.
*/
public DeployBeanDescriptor<?> getTargetDeploy() {
return desc.getDeploy(targetType).getDescriptor();
}
/**
* Return the type of the target.
* <p>
* This is the class of the associated bean, or beans contained in a list,
* set or map.
* </p>
*/
public Class<T> getTargetType() {
return targetType;
}
/**
* Return a literal expression that is added to the query that lazy loads
* the collection.
*/
public String getExtraWhere() {
return extraWhere;
}
/**
* Set a literal expression to add to the query that lazy loads the
* collection.
*/
public void setExtraWhere(String extraWhere) {
this.extraWhere = extraWhere;
}
/**
* return the join to use for the bean.
*/
public DeployTableJoin getTableJoin() {
return tableJoin;
}
/**
* Return the BeanTable for this association.
* <p>
* This has the table name which is used to determine the relationship for
* this association.
* </p>
*/
public BeanTable getBeanTable() {
return beanTable;
}
/**
* Set the bean table.
*/
public void setBeanTable(BeanTable beanTable) {
this.beanTable = beanTable;
getTableJoin().setTable(beanTable.getBaseTable());
}
/**
* Get the persist info.
*/
public BeanCascadeInfo getCascadeInfo() {
return cascadeInfo;
}
/**
* Return the mappedBy deployment attribute.
* <p>
* This is the name of the property in the 'detail' bean that maps back to
* this 'master' bean.
* </p>
*/
public String getMappedBy() {
return mappedBy;
}
/**
* Set mappedBy deployment attribute.
*/
public void setMappedBy(String mappedBy) {
if (!"".equals(mappedBy)) {
this.mappedBy = mappedBy;
}
}
/**
* Set DocStoreEmbedded deployment information.
*/
public void setDocStoreEmbedded(String embeddedDoc) {
this.docStoreDoc = embeddedDoc;
}
public String getDocStoreDoc() {
return docStoreDoc;
}
}
@@ -0,0 +1,209 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebeaninternal.server.deploy.ManyType;
import io.ebeaninternal.server.deploy.TableJoin;
/**
* Property mapped to a List Set or Map.
*/
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
/**
* The type of the many, set, list or map.
*/
final ManyType manyType;
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
/**
* Flag to indicate manyToMany relationship.
*/
boolean manyToMany;
/**
* Flag to indicate this is a unidirectional relationship.
*/
boolean unidirectional;
/**
* Join for manyToMany intersection table.
*/
DeployTableJoin intersectionJoin;
/**
* For ManyToMany this is the Inverse join used to build reference queries.
*/
DeployTableJoin inverseJoin;
String fetchOrderBy;
String mapKey;
String intersectionDraftTable;
/**
* Create this property.
*/
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
super(desc, targetType);
this.manyType = manyType;
}
/**
* When generics is not used for manyType you can specify via annotations.
* <p>
* Really only expect this for Scala due to a Scala compiler bug at the moment.
* Otherwise I'd probably not bother support this.
* </p>
*/
@SuppressWarnings("unchecked")
public void setTargetType(Class<?> cls){
this.targetType = (Class<T>)cls;
}
/**
* Return the many type.
*/
public ManyType getManyType() {
return manyType;
}
/**
* Return true if this is many to many.
*/
public boolean isManyToMany() {
return manyToMany;
}
/**
* Set to true if this is a many to many.
*/
public void setManyToMany() {
this.manyToMany = true;
}
/**
* Return the mode for listening to changes to the List Set or Map.
*/
public ModifyListenMode getModifyListenMode() {
return modifyListenMode;
}
/**
* Set the mode for listening to changes to the List Set or Map.
*/
public void setModifyListenMode(ModifyListenMode modifyListenMode) {
this.modifyListenMode = modifyListenMode;
}
/**
* Return true if this is a unidirectional relationship.
*/
public boolean isUnidirectional() {
return unidirectional;
}
/**
* Set to true if this is a unidirectional relationship.
*/
public void setUnidirectional() {
this.unidirectional = true;
}
/**
* Create the immutable version of the intersection join.
*/
public TableJoin createIntersectionTableJoin() {
if (intersectionJoin != null){
return new TableJoin(intersectionJoin);
} else {
return null;
}
}
/**
* Create the immutable version of the inverse join.
*/
public TableJoin createInverseTableJoin() {
if (inverseJoin != null){
return new TableJoin(inverseJoin);
} else {
return null;
}
}
/**
* ManyToMany only, join from local table to intersection table.
*/
public DeployTableJoin getIntersectionJoin() {
return intersectionJoin;
}
public DeployTableJoin getInverseJoin() {
return inverseJoin;
}
/**
* ManyToMany only, join from local table to intersection table.
*/
public void setIntersectionJoin(DeployTableJoin intersectionJoin) {
this.intersectionJoin = intersectionJoin;
}
/**
* ManyToMany only, join from foreign table to intersection table.
*/
public void setInverseJoin(DeployTableJoin inverseJoin) {
this.inverseJoin = inverseJoin;
}
/**
* Return the order by clause used to order the fetching of the data for
* this list, set or map.
*/
public String getFetchOrderBy() {
return fetchOrderBy;
}
/**
* Return the default mapKey when returning a Map.
*/
public String getMapKey() {
return mapKey;
}
/**
* Set the default mapKey to use when returning a Map.
*/
public void setMapKey(String mapKey) {
if (mapKey != null && !mapKey.isEmpty()) {
this.mapKey = mapKey;
}
}
/**
* Set the order by clause used to order the fetching or the data for this
* list, set or map.
*/
public void setFetchOrderBy(String orderBy) {
if (orderBy != null && !orderBy.isEmpty()) {
fetchOrderBy = orderBy;
}
}
/**
* Return a draft table for intersection between 2 @Draftable entities.
*/
public String getIntersectionDraftTable() {
return (intersectionDraftTable != null) ? intersectionDraftTable : intersectionJoin.getTable();
}
/**
* ManyToMany between 2 @Draftable entities to also need draft intersection table.
*/
public void setIntersectionDraftTable() {
this.intersectionDraftTable = intersectionJoin.getTable()+"_draft";
}
}
@@ -0,0 +1,118 @@
package io.ebeaninternal.server.deploy.meta;
/**
* Property mapped to a joined bean.
*/
public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
private boolean oneToOne;
private boolean oneToOneExported;
private boolean importedPrimaryKey;
private DeployBeanEmbedded deployEmbedded;
private String columnPrefix;
/**
* Create the property.
*/
public DeployBeanPropertyAssocOne(DeployBeanDescriptor<?> desc, Class<T> targetType) {
super(desc, targetType);
}
/**
* Return the deploy information specifically for the deployment
* of Embedded beans.
*/
public DeployBeanEmbedded getDeployEmbedded() {
// deployment should be single threaded
if (deployEmbedded == null) {
deployEmbedded = new DeployBeanEmbedded();
}
return deployEmbedded;
}
/**
* Return true if this has multiple properties (expected for embedded id).
*/
public boolean isCompound() {
// just checking for compound and not doing numeric check at this stage
return getDeployEmbedded().getPropertyColumnMap().size() > 1;
}
@Override
public String getDbColumn() {
DeployTableJoinColumn[] columns = tableJoin.columns();
if (columns.length == 1) {
return columns[0].getLocalDbColumn();
}
return super.getDbColumn();
}
/**
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
*/
public boolean isOneToOne() {
return oneToOne;
}
/**
* Set to true if this is a OneToOne.
*/
public void setOneToOne() {
this.oneToOne = true;
}
/**
* Return true if this is the exported side of a OneToOne.
*/
public boolean isOneToOneExported() {
return oneToOneExported;
}
/**
* Set to true if this is the exported side of a OneToOne. This means
* it doesn't 'own' the foreign key column. A OneToMany without the many.
*/
public void setOneToOneExported() {
this.oneToOneExported = true;
}
/**
* Return true if this is part of the primary key.
*/
public boolean isImportedPrimaryKey() {
return importedPrimaryKey;
}
/**
* Set to true if this is part of the primary key.
*/
void setImportedPrimaryKey(DeployBeanProperty primaryKey) {
this.importedPrimaryKey = true;
String dbColumn = primaryKey.getDbColumn();
if (dbColumn != null) {
// change join db column if matched by property name
tableJoin.setLocalColumn(dbColumn);
}
}
@Override
public void setSqlFormula(String formulaSelect, String formulaJoin) {
super.setSqlFormula(formulaSelect, formulaJoin);
DeployTableJoinColumn[] columns = tableJoin.columns();
if (columns.length == 1) {
columns[0].setLocalSqlFormula(formulaSelect);
}
}
public void setColumnPrefix(String columnPrefix) {
this.columnPrefix = columnPrefix;
}
public String getColumnPrefix() {
return columnPrefix;
}
}
@@ -0,0 +1,434 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanDescriptorMap;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.type.ScalarTypeString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Helper object to classify BeanProperties into appropriate lists.
*/
public class DeployBeanPropertyLists {
private static final Logger logger = LoggerFactory.getLogger(DeployBeanPropertyLists.class);
private BeanProperty versionProperty;
private BeanProperty unmappedJson;
private BeanProperty draft;
private BeanProperty draftDirty;
private BeanProperty tenant;
private final BeanDescriptor<?> desc;
private final LinkedHashMap<String, BeanProperty> propertyMap;
private final List<BeanProperty> ids = new ArrayList<>();
private final List<BeanProperty> local = new ArrayList<>();
private final List<BeanProperty> mutable = new ArrayList<>();
private final List<BeanPropertyAssocMany<?>> manys = new ArrayList<>();
private final List<BeanProperty> nonManys = new ArrayList<>();
private final List<BeanPropertyAssocOne<?>> ones = new ArrayList<>();
private final List<BeanPropertyAssocOne<?>> onesImported = new ArrayList<>();
private final List<BeanPropertyAssocOne<?>> embedded = new ArrayList<>();
private final List<BeanProperty> baseScalar = new ArrayList<>();
private final List<BeanProperty> transients = new ArrayList<>();
private final List<BeanProperty> nonTransients = new ArrayList<>();
private final TableJoin[] tableJoins;
private final BeanPropertyAssocOne<?> unidirectional;
@SuppressWarnings({ "unchecked", "rawtypes" })
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
this.desc = desc;
setImportedPrimaryKeys(deploy);
DeployBeanPropertyAssocOne<?> deployUnidirectional = deploy.getUnidirectional();
if (deployUnidirectional == null) {
unidirectional = null;
} else {
unidirectional = new BeanPropertyAssocOne(owner, desc, deployUnidirectional);
}
this.propertyMap = new LinkedHashMap<>();
// see if there is a discriminator property we should add
String discriminatorColumn = null;
BeanProperty discProperty = null;
InheritInfo inheritInfo = deploy.getInheritInfo();
if (inheritInfo != null) {
// Create a BeanProperty for the discriminator column to support
// using RawSql queries with inheritance
discriminatorColumn = inheritInfo.getDiscriminatorColumn();
DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, new ScalarTypeString(), null);
discDeployProp.setDiscriminator();
discDeployProp.setName(discriminatorColumn);
discDeployProp.setDbColumn(discriminatorColumn);
// only register it in the propertyMap. This might not be used if
// an explicit property is mapped to the discriminator on the bean
discProperty = new BeanProperty(desc, discDeployProp);
}
for (DeployBeanProperty prop : deploy.propertiesAll()) {
if (discriminatorColumn != null && discriminatorColumn.equals(prop.getDbColumn())) {
// we have an explicit property mapped to the discriminator column
prop.setDiscriminator();
discProperty = null;
}
BeanProperty beanProp = createBeanProperty(owner, prop);
propertyMap.put(beanProp.getName(), beanProp);
}
int order = 0;
for (BeanProperty prop : propertyMap.values()) {
prop.setDeployOrder(order++);
allocateToList(prop);
}
if (discProperty != null) {
// put the discriminator property into the property map only
// (after the real properties have been organised into their lists)
propertyMap.put(discProperty.getName(), discProperty);
}
List<DeployTableJoin> deployTableJoins = deploy.getTableJoins();
tableJoins = new TableJoin[deployTableJoins.size()];
for (int i = 0; i < deployTableJoins.size(); i++) {
tableJoins[i] = new TableJoin(deployTableJoins.get(i));
}
}
/**
* Find and set imported primary keys.
* <p>
* This is where @ManyToOne properties maps to a PFK (Primary and foreign key).
* Perform the match by naming convention on property name and db column.
* </p>
*/
private void setImportedPrimaryKeys(DeployBeanDescriptor<?> deploy) {
List<DeployBeanProperty> ids = deploy.propertiesId();
if (ids.size() == 1) {
DeployBeanProperty id = ids.get(0);
if (id instanceof DeployBeanPropertyAssocOne<?>) {
// only interested if the primary key is a compound key
DeployBeanDescriptor<?> targetDeploy = ((DeployBeanPropertyAssocOne<?>) id).getTargetDeploy();
for (DeployBeanPropertyAssocOne<?> assoc : deploy.propertiesAssocOne()) {
DeployBeanProperty pkMatch = targetDeploy.findMatch(assoc.getName(), assoc.getDbColumn());
if (pkMatch != null) {
assoc.setImportedPrimaryKey(pkMatch);
}
}
}
}
}
/**
* Return the unidirectional.
*/
public BeanPropertyAssocOne<?> getUnidirectional() {
return unidirectional;
}
/**
* Allocate the property to a list.
*/
private void allocateToList(BeanProperty prop) {
if (prop.isTransient()) {
transients.add(prop);
if (prop.isDraft()) {
draft = prop;
}
if (prop.isUnmappedJson()) {
unmappedJson = prop;
}
return;
}
if (prop.isId()) {
ids.add(prop);
return;
} else {
nonTransients.add(prop);
}
if (prop.isMutableScalarType()) {
mutable.add(prop);
}
if (desc.getInheritInfo() != null && prop.isLocal()) {
local.add(prop);
}
if (prop instanceof BeanPropertyAssocMany<?>) {
manys.add((BeanPropertyAssocMany<?>)prop);
} else {
nonManys.add(prop);
if (prop instanceof BeanPropertyAssocOne<?>) {
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) prop;
if (prop.isEmbedded()) {
embedded.add(assocOne);
} else {
ones.add(assocOne);
if (!assocOne.isOneToOneExported()) {
onesImported.add(assocOne);
}
}
} else {
// its a "base" property...
if (prop.isVersion()) {
if (versionProperty == null) {
versionProperty = prop;
} else {
logger.warn("Multiple @Version properties - property " + prop.getFullBeanName() + " not treated as a version property");
}
} else if (prop.isDraftDirty()) {
draftDirty = prop;
} else if (prop.isTenantId()) {
tenant = prop;
}
if (!prop.isAggregation()) {
baseScalar.add(prop);
}
}
}
}
public LinkedHashMap<String, BeanProperty> getPropertyMap() {
return propertyMap;
}
public TableJoin[] getTableJoin() {
return tableJoins;
}
/**
* Return the base scalar properties (excludes Id and secondary table
* properties).
*/
public BeanProperty[] getBaseScalar() {
return baseScalar.toArray(new BeanProperty[baseScalar.size()]);
}
public BeanProperty getId() {
if (ids.size() > 1) {
String msg = "Issue with bean "+desc+". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
+" Please email the ebean google group if you need further clarification.";
throw new IllegalStateException(msg);
}
if (ids.isEmpty()) {
return null;
}
return ids.get(0);
}
public BeanProperty[] getNonTransients() {
return nonTransients.toArray(new BeanProperty[nonTransients.size()]);
}
public BeanProperty[] getTransients() {
return transients.toArray(new BeanProperty[transients.size()]);
}
public BeanProperty getVersionProperty() {
return versionProperty;
}
public BeanProperty[] getLocal() {
return local.toArray(new BeanProperty[local.size()]);
}
public BeanProperty[] getMutable() {
return mutable.toArray(new BeanProperty[mutable.size()]);
}
public BeanPropertyAssocOne<?>[] getEmbedded() {
return embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
}
public BeanPropertyAssocOne<?>[] getOneImported() {
return onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
}
public BeanPropertyAssocOne<?>[] getOnes() {
return ones.toArray(new BeanPropertyAssocOne[ones.size()]);
}
public BeanPropertyAssocOne<?>[] getOneExportedSave() {
return getOne(false, Mode.Save);
}
public BeanPropertyAssocOne<?>[] getOneExportedDelete() {
return getOne(false, Mode.Delete);
}
public BeanPropertyAssocOne<?>[] getOneImportedSave() {
return getOne(true, Mode.Save);
}
public BeanPropertyAssocOne<?>[] getOneImportedDelete() {
return getOne(true, Mode.Delete);
}
public BeanProperty[] getNonMany() {
return nonManys.toArray(new BeanProperty[nonManys.size()]);
}
public BeanPropertyAssocMany<?>[] getMany() {
return manys.toArray(new BeanPropertyAssocMany[manys.size()]);
}
public BeanPropertyAssocMany<?>[] getManySave() {
return getMany(Mode.Save);
}
public BeanPropertyAssocMany<?>[] getManyDelete() {
return getMany(Mode.Delete);
}
public BeanPropertyAssocMany<?>[] getManyToMany() {
return getMany2Many();
}
public BeanProperty getDraftDirty() {
return draftDirty;
}
public BeanProperty getUnmappedJson() {
return unmappedJson;
}
public BeanProperty getDraft() {
return draft;
}
public BeanProperty getSoftDeleteProperty() {
for (BeanProperty prop: nonManys) {
if (prop.isSoftDelete()) {
return prop;
}
}
return null;
}
public BeanProperty getTenant() {
return tenant;
}
/**
* Mode used to determine which BeanPropertyAssoc to include.
*/
private enum Mode {
Save, Delete
}
private BeanPropertyAssocOne<?>[] getOne(boolean imported, Mode mode) {
ArrayList<BeanPropertyAssocOne<?>> list = new ArrayList<>();
for (BeanPropertyAssocOne<?> prop : ones) {
if (imported != prop.isOneToOneExported()) {
switch (mode) {
case Save:
if (prop.getCascadeInfo().isSave()) {
list.add(prop);
}
break;
case Delete:
if (prop.getCascadeInfo().isDelete()) {
list.add(prop);
}
break;
default:
break;
}
}
}
return (BeanPropertyAssocOne[]) list.toArray(new BeanPropertyAssocOne[list.size()]);
}
private BeanPropertyAssocMany<?>[] getMany2Many() {
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<>();
for (BeanPropertyAssocMany<?> prop : manys) {
if (prop.isManyToMany()) {
list.add(prop);
}
}
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
}
private BeanPropertyAssocMany<?>[] getMany(Mode mode) {
ArrayList<BeanPropertyAssocMany<?>> list = new ArrayList<>();
for (BeanPropertyAssocMany<?> prop : manys) {
switch (mode) {
case Save:
if (prop.getCascadeInfo().isSave() || prop.isManyToMany()
|| ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
// Note ManyToMany always included as we always 'save'
// the relationship via insert/delete of intersection table
// REMOVALS means including PrivateOwned relationships
list.add(prop);
}
break;
case Delete:
if (prop.getCascadeInfo().isDelete() || ModifyListenMode.REMOVALS.equals(prop.getModifyListenMode())) {
// REMOVALS means including PrivateOwned relationships
list.add(prop);
}
break;
default:
break;
}
}
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private BeanProperty createBeanProperty(BeanDescriptorMap owner, DeployBeanProperty deployProp) {
if (deployProp instanceof DeployBeanPropertyAssocOne) {
return new BeanPropertyAssocOne(owner, desc, (DeployBeanPropertyAssocOne) deployProp);
}
if (deployProp instanceof DeployBeanPropertySimpleCollection<?>) {
return new BeanPropertySimpleCollection(desc, (DeployBeanPropertySimpleCollection) deployProp);
}
if (deployProp instanceof DeployBeanPropertyAssocMany) {
return new BeanPropertyAssocMany(desc, (DeployBeanPropertyAssocMany) deployProp);
}
return new BeanProperty(desc, deployProp);
}
}
@@ -0,0 +1,29 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebeaninternal.server.deploy.ManyType;
public class DeployBeanPropertySimpleCollection<T> extends DeployBeanPropertyAssocMany<T> {
public DeployBeanPropertySimpleCollection(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
super(desc, targetType, manyType);
this.modifyListenMode = ModifyListenMode.ALL;
}
/**
* Returns false as never a ManyToMany.
*/
@Override
public boolean isManyToMany() {
return false;
}
/**
* Returns true as always Unidirectional.
*/
@Override
public boolean isUnidirectional() {
return true;
}
}
@@ -0,0 +1,90 @@
package io.ebeaninternal.server.deploy.meta;
import java.util.List;
import io.ebeaninternal.server.deploy.BeanDescriptorMap;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
/**
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
* recursion issues due to the potentially bi-directional and circular
* relationships between beans.
* <p>
* It holds the main deployment information and not all the detail that is held
* in a BeanDescriptor.
* </p>
*/
public class DeployBeanTable {
private final Class<?> beanType;
/**
* The base table.
*/
private String baseTable;
private List<DeployBeanProperty> idProperties;
/**
* Create the BeanTable.
*/
public DeployBeanTable(Class<?> beanType) {
this.beanType = beanType;
}
/**
* Return the base table for this BeanTable.
* This is used to determine the join information
* for associations.
*/
public String getBaseTable() {
return baseTable;
}
/**
* Set the base table for this BeanTable.
*/
public void setBaseTable(String baseTable) {
this.baseTable = baseTable;
}
/**
* Return the id properties.
*/
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
BeanProperty[] props = new BeanProperty[idProperties.size()];
for (int i = 0; i < idProperties.size(); i++) {
props[i] = createProperty(owner, idProperties.get(i));
}
return props;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop){
if (prop instanceof DeployBeanPropertyAssocOne<?>){
return new BeanPropertyAssocOne(owner, (DeployBeanPropertyAssocOne<?>)prop);
} else {
return new BeanProperty(prop);
}
}
/**
* Set the Id properties.
*/
public void setIdProperties(List<DeployBeanProperty> idProperties) {
this.idProperties = idProperties;
}
/**
* Return the class for this beanTable.
*/
public Class<?> getBeanType() {
return beanType;
}
}
@@ -0,0 +1,177 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebeaninternal.server.deploy.BeanTable;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.query.SqlJoinType;
import javax.persistence.JoinColumn;
import java.util.ArrayList;
import java.util.Set;
/**
* Represents a join to another table during deployment phase.
* <p>
* This gets converted into a immutable TableJoin when complete.
* </p>
*/
public class DeployTableJoin {
/**
* The joined table.
*/
private String table;
/**
* The type of join. LEFT JOIN etc.
*/
private SqlJoinType type = SqlJoinType.INNER;
/**
* The list of join column pairs. Used to generate the on clause.
*/
private ArrayList<DeployTableJoinColumn> columns = new ArrayList<>(4);
private InheritInfo inheritInfo;
/**
* Create a DeployTableJoin.
*/
public DeployTableJoin() {
}
public String toString() {
return type + " " + table + " " + columns;
}
/**
* Return true if the JoinOnPair have been set.
*/
public boolean hasJoinColumns() {
return !columns.isEmpty();
}
/**
* Copy all the columns to this join potentially reversing the columns.
*/
public void setColumns(DeployTableJoinColumn[] cols, boolean reverse) {
columns = new ArrayList<>();
for (DeployTableJoinColumn col : cols) {
addJoinColumn(col.copy(reverse));
}
}
/**
* Add a join pair
*/
public void addJoinColumn(DeployTableJoinColumn pair) {
columns.add(pair);
}
/**
* Add a JoinColumn
* <p>
* The order is generally true for OneToMany and false for ManyToOne relationships.
* </p>
*/
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
if (!"".equals(jc.table())) {
setTable(jc.table());
}
if (!"".equals(jc.name()) || !"".equals(jc.referencedColumnName())) {
// only add the join column details when name or referencedColumnName is specified
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
}
}
/**
* Add a JoinColumn array.
*/
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
for (JoinColumn aJcArray : jcArray) {
addJoinColumn(order, aJcArray, beanTable);
}
}
/**
* Add a JoinColumn set.
*/
public void addJoinColumn(boolean order, Set<JoinColumn> joinColumns, BeanTable beanTable) {
for (JoinColumn joinColumn : joinColumns) {
addJoinColumn(order, joinColumn, beanTable);
}
}
/**
* Return the join columns.
*/
public DeployTableJoinColumn[] columns() {
return columns.toArray(new DeployTableJoinColumn[columns.size()]);
}
/**
* Return the joined table name.
*/
public String getTable() {
return table;
}
/**
* set the joined table name.
*/
public void setTable(String table) {
this.table = table;
}
/**
* Return the type of join. LEFT OUTER JOIN etc.
*/
public SqlJoinType getType() {
return type;
}
public void setType(SqlJoinType type) {
this.type = type;
}
public DeployTableJoin createInverse(String tableName) {
DeployTableJoin inverse = new DeployTableJoin();
return copyInternal(inverse, true, tableName, true);
}
public void copyTo(DeployTableJoin destJoin, boolean reverse, String tableName) {
copyInternal(destJoin, reverse, tableName, true);
}
public void copyWithoutType(DeployTableJoin destJoin, boolean reverse, String tableName) {
copyInternal(destJoin, reverse, tableName, false);
}
private DeployTableJoin copyInternal(DeployTableJoin destJoin, boolean reverse, String tableName, boolean withType) {
destJoin.setTable(tableName);
if (withType) {
destJoin.setType(type);
}
destJoin.setColumns(columns(), reverse);
return destJoin;
}
public InheritInfo getInheritInfo() {
return inheritInfo;
}
public void setInheritInfo(InheritInfo inheritInfo) {
this.inheritInfo = inheritInfo;
}
/**
* Change the join column (based on imported primary key match on property name etc).
*/
void setLocalColumn(String dbColumn) {
if (columns.size() == 1) {
columns.get(0).setLocalDbColumn(dbColumn);
}
}
}
@@ -0,0 +1,185 @@
package io.ebeaninternal.server.deploy.meta;
import javax.persistence.JoinColumn;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanTable;
/**
* A join pair of local and foreign properties.
*/
public class DeployTableJoinColumn {
/**
* The local database column name.
*/
String localDbColumn;
/**
* SQL formula used for local column
*/
String localSqlFormula;
/**
* The foreign database column name.
*/
String foreignDbColumn;
/**
* SQL formula used for foreign column
*/
String foreignSqlFormula;
boolean insertable;
boolean updateable;
/**
* Construct when automatically determining the join.
* <p>
* Assume that we want the foreign key to be insertable and updateable.
* </p>
*/
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn) {
this(localDbColumn, foreignDbColumn, true, true);
}
/**
* Construct with explicit insertable and updateable flags.
*/
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
this.localDbColumn = nullEmptyString(localDbColumn);
this.foreignDbColumn = nullEmptyString(foreignDbColumn);
this.insertable = insertable;
this.updateable = updateable;
}
public void setLocalSqlFormula(String localSqlFormula) {
if (localSqlFormula != null) {
this.localSqlFormula = localSqlFormula;
this.localDbColumn = null;
this.insertable = false;
this.updateable = false;
}
}
public String getLocalSqlFormula() {
return localSqlFormula;
}
public void setForeignSqlFormula(String foreignSqlFormula) {
if (foreignSqlFormula != null) {
this.foreignSqlFormula = foreignSqlFormula;
this.foreignDbColumn = null;
this.insertable = false;
this.updateable = false;
}
}
public String getForeignSqlFormula() {
return foreignSqlFormula;
}
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
setReferencedColumn(beanTable);
if (!order){
reverse();
}
}
private void setReferencedColumn(BeanTable beanTable){
if (localDbColumn == null){
BeanProperty[] idProperties = beanTable.getIdProperties();
if (idProperties.length == 1){
localDbColumn = idProperties[0].getDbColumn();
}
}
}
/**
* Reverse the direction of the join.
*/
public DeployTableJoinColumn reverse() {
String temp = localDbColumn;
localDbColumn = foreignDbColumn;
foreignDbColumn = temp;
temp = localSqlFormula;
localSqlFormula = foreignSqlFormula;
foreignSqlFormula = temp;
return this;
}
/**
* Helper method to null out empty strings.
*/
private String nullEmptyString(String s){
if ("".equals(s)){
return null;
}
return s;
}
public DeployTableJoinColumn copy(boolean reverse) {
// Note that the insertable and updateable are just copied
// which may not always be the correct thing to do
// but will leave it like this for now
DeployTableJoinColumn ret;
if (reverse){
ret = new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable);
ret.setLocalSqlFormula(foreignSqlFormula);
ret.setForeignSqlFormula(localSqlFormula);
} else {
ret = new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
ret.setLocalSqlFormula(localSqlFormula);
ret.setForeignSqlFormula(foreignSqlFormula);
}
return ret;
}
public String toString() {
return localDbColumn + " = " + foreignDbColumn;
}
/**
* Return true if this column should be insertable.
*/
public boolean isInsertable() {
return insertable;
}
/**
* Return true if this column should be updateable.
*/
public boolean isUpdateable() {
return updateable;
}
/**
* Return the foreign database column name.
*/
public String getForeignDbColumn() {
return foreignDbColumn;
}
/**
* Return the local database column name.
*/
public String getLocalDbColumn() {
return localDbColumn;
}
/**
* Set the local database column name.
*/
public void setLocalDbColumn(String localDbColumn) {
this.localDbColumn = localDbColumn;
}
}
@@ -0,0 +1,10 @@
<html>
<head>
<meta HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<title>Temporary objects used to collect deployment information</title>
</head>
<body BGCOLOR="#ffffff">
Temporary objects used to collect deployment information
</body>
</html>