package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.deploy.parse.DeployInheritInfo;
import io.ebeaninternal.server.query.SqlTreeProperties;
import java.lang.reflect.Modifier;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
Represents a node in the Inheritance tree. Holds information regarding Super Subclass support.
/**
* Represents a node in the Inheritance tree. Holds information regarding Super Subclass support.
*/
public class InheritInfo {
private final String discriminatorStringValue;
private final Object discriminatorValue;
private final String discriminatorColumn;
private final int discriminatorType;
private final int discriminatorLength;
private final String columnDefn;
private final String where;
private final Class<?> type;
private final ArrayList<InheritInfo> children = new ArrayList<>();
Map of discriminator values to InheritInfo.
/**
* Map of discriminator values to InheritInfo.
*/
private final HashMap<String, InheritInfo> discMap;
Map of class types to InheritInfo (taking into account subclass proxy classes).
/**
* Map of class types to InheritInfo (taking into account subclass proxy classes).
*/
private final HashMap<String, InheritInfo> typeMap;
private final InheritInfo parent;
private final InheritInfo root;
private BeanDescriptor<?> descriptor;
public InheritInfo(InheritInfo r, InheritInfo parent, DeployInheritInfo deploy) {
this.parent = parent;
this.type = deploy.getType();
this.discriminatorColumn = InternString.intern(deploy.getColumnName(parent));
this.discriminatorValue = deploy.getDiscriminatorObjectValue();
this.discriminatorStringValue = deploy.getDiscriminatorStringValue();
this.discriminatorType = deploy.getDiscriminatorType(parent);
this.discriminatorLength = deploy.getColumnLength(parent);
this.columnDefn = deploy.getColumnDefn();
this.where = InternString.intern(deploy.getWhere());
if (r == null) {
// this is a root node
root = this;
discMap = new HashMap<>();
typeMap = new HashMap<>();
registerWithRoot(this);
} else {
this.root = r;
// register with the root node...
discMap = null;
typeMap = null;
root.registerWithRoot(this);
}
}
Visit all the children in the inheritance tree.
/**
* Visit all the children in the inheritance tree.
*/
public void visitChildren(InheritInfoVisitor visitor) {
for (InheritInfo child : children) {
visitor.visit(child);
child.visitChildren(visitor);
}
}
Append check constraint values for the entire inheritance hierarchy.
/**
* Append check constraint values for the entire inheritance hierarchy.
*/
public void appendCheckConstraintValues(final String propertyName, final Set<String> checkConstraintValues) {
visitChildren(inheritInfo -> {
BeanProperty prop = inheritInfo.desc().getBeanProperty(propertyName);
if (prop != null) {
Set<String> values = prop.getDbCheckConstraintValues();
if (values != null) {
checkConstraintValues.addAll(values);
}
}
});
}
return true if anything in the inheritance hierarchy has a relationship with a save cascade on
it.
/**
* return true if anything in the inheritance hierarchy has a relationship with a save cascade on
* it.
*/
public boolean isSaveRecurseSkippable() {
return root.isNodeSaveRecurseSkippable();
}
private boolean isNodeSaveRecurseSkippable() {
if (!descriptor.isSaveRecurseSkippable()) {
return false;
}
for (InheritInfo child : children) {
if (!child.isNodeSaveRecurseSkippable()) {
return false;
}
}
return true;
}
return true if anything in the inheritance hierarchy has a relationship with a delete cascade
on it.
/**
* return true if anything in the inheritance hierarchy has a relationship with a delete cascade
* on it.
*/
public boolean isDeleteRecurseSkippable() {
return root.isNodeDeleteRecurseSkippable();
}
private boolean isNodeDeleteRecurseSkippable() {
if (!descriptor.isDeleteRecurseSkippable()) {
return false;
}
for (InheritInfo child : children) {
if (!child.isNodeDeleteRecurseSkippable()) {
return false;
}
}
return true;
}
Set the descriptor for this node.
/**
* Set the descriptor for this node.
*/
public void setDescriptor(BeanDescriptor<?> descriptor) {
this.descriptor = descriptor;
}
Return the associated BeanDescriptor for this node.
/**
* Return the associated BeanDescriptor for this node.
*/
public BeanDescriptor<?> desc() {
return descriptor;
}
Return the local properties for this node in the hierarchy.
/**
* Return the local properties for this node in the hierarchy.
*/
public BeanProperty[] localProperties() {
return descriptor.propertiesLocal();
}
Return the children.
/**
* Return the children.
*/
public ArrayList<InheritInfo> getChildren() {
return children;
}
Get the bean property additionally looking in the sub types.
/**
* Get the bean property additionally looking in the sub types.
*/
public BeanProperty findSubTypeProperty(String propertyName) {
BeanProperty prop;
for (InheritInfo childInfo : children) {
// recursively search this child bean descriptor
prop = childInfo.desc().findProperty(propertyName);
if (prop != null) {
return prop;
}
}
return null;
}
Add the local properties for each sub class below this one.
/**
* Add the local properties for each sub class below this one.
*/
public void addChildrenProperties(SqlTreeProperties selectProps) {
for (InheritInfo childInfo : children) {
selectProps.add(childInfo.descriptor.propertiesLocal());
childInfo.addChildrenProperties(selectProps);
}
}
Return the associated InheritInfo for this DB row read.
/**
* Return the associated InheritInfo for this DB row read.
*/
public InheritInfo readType(DbReadContext ctx) throws SQLException {
String discValue = ctx.getDataReader().getString();
return readType(discValue);
}
Return the associated InheritInfo for this discriminator value.
/**
* Return the associated InheritInfo for this discriminator value.
*/
public InheritInfo readType(String discValue) {
if (discValue == null) {
return null;
}
InheritInfo typeInfo = root.getType(discValue);
if (typeInfo == null) {
throw new PersistenceException("Inheritance type for discriminator value [" + discValue + "] was not found?");
}
return typeInfo;
}
Return the associated InheritInfo for this bean type.
/**
* Return the associated InheritInfo for this bean type.
*/
public InheritInfo readType(Class<?> beanType) {
InheritInfo typeInfo = root.getTypeByClass(beanType);
if (typeInfo == null) {
throw new PersistenceException("Inheritance type for bean type [" + beanType.getName() + "] was not found?");
}
return typeInfo;
}
Create an EntityBean for this type.
/**
* Create an EntityBean for this type.
*/
public EntityBean createEntityBean() {
return descriptor.createEntityBean();
}
Return the IdBinder for this type.
/**
* Return the IdBinder for this type.
*/
public IdBinder getIdBinder() {
return descriptor.getIdBinder();
}
return the type.
/**
* return the type.
*/
public Class<?> getType() {
return type;
}
Return the root node of the tree.
The root has a map of discriminator values to types.
/**
* Return the root node of the tree.
* <p>
* The root has a map of discriminator values to types.
* </p>
*/
public InheritInfo getRoot() {
return root;
}
Return the parent node.
/**
* Return the parent node.
*/
public InheritInfo getParent() {
return parent;
}
Return true if this is the root node.
/**
* Return true if this is the root node.
*/
public boolean isRoot() {
return parent == null;
}
Return true if this is considered a concrete type in the inheritance hierarchy.
/**
* Return true if this is considered a concrete type in the inheritance hierarchy.
*/
public boolean isConcrete() {
return !Modifier.isAbstract(type.getModifiers());
}
For a discriminator get the inheritance information for this tree.
/**
* For a discriminator get the inheritance information for this tree.
*/
public InheritInfo getType(String discValue) {
return discMap.get(discValue);
}
Return the InheritInfo for the given bean type.
/**
* Return the InheritInfo for the given bean type.
*/
private InheritInfo getTypeByClass(Class<?> beanType) {
return typeMap.get(beanType.getName());
}
private void registerWithRoot(InheritInfo info) {
if (info.getDiscriminatorStringValue() != null) {
String stringDiscValue = info.getDiscriminatorStringValue();
discMap.put(stringDiscValue, info);
}
typeMap.put(info.getType().getName(), info);
}
Add a child node.
/**
* Add a child node.
*/
public void addChild(InheritInfo childInfo) {
children.add(childInfo);
}
Return the derived where for the discriminator.
/**
* Return the derived where for the discriminator.
*/
public String getWhere() {
return where;
}
Return the column name of the discriminator.
/**
* Return the column name of the discriminator.
*/
public String getDiscriminatorColumn() {
return discriminatorColumn;
}
Return the sql type of the discriminator value.
/**
* Return the sql type of the discriminator value.
*/
public int getDiscriminatorType() {
return discriminatorType;
}
Return the length of the discriminator column.
/**
* Return the length of the discriminator column.
*/
public int getColumnLength() {
return discriminatorLength;
}
Return the explicit column definition.
/**
* Return the explicit column definition.
*/
public String getColumnDefn() {
return columnDefn;
}
Return the discriminator value for this node.
/**
* Return the discriminator value for this node.
*/
public String getDiscriminatorStringValue() {
return discriminatorStringValue;
}
public Object getDiscriminatorValue() {
return discriminatorValue;
}
@Override
public String toString() {
return "InheritInfo[" + type.getName() + "] disc[" + discriminatorStringValue + "]";
}
}