org.tentackle.model.impl.EntityImpl Maven / Gradle / Ivy
/*
* Tentackle - http://www.tentackle.org.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.tentackle.model.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import org.tentackle.common.BasicStringHelper;
import org.tentackle.common.Compare;
import org.tentackle.common.Constants;
import org.tentackle.model.Attribute;
import org.tentackle.model.AttributeSorting;
import org.tentackle.model.DataType;
import org.tentackle.model.Entity;
import org.tentackle.model.Index;
import org.tentackle.model.InheritanceType;
import org.tentackle.model.Integrity;
import org.tentackle.model.ModelException;
import org.tentackle.model.Relation;
import org.tentackle.model.SourceInfo;
import org.tentackle.model.parser.ConfigurationLine;
import org.tentackle.sql.Backend;
/**
* The entity model implementation.
*
* @author harald
*/
public class EntityImpl implements Entity, Comparable {
/** name = ... */
static final String NAME = "NAME";
/** id = ... */
static final String ID = "ID";
/** table = ... */
static final String TABLE = "TABLE";
/** alias = ... */
static final String ALIAS = "ALIAS";
/** integrity = ... */
static final String INTEGRITY = "INTEGRITY";
/** inheritance = ... */
static final String INHERITANCE = "INHERITANCE";
/** extends = ... */
static final String EXTENDS = "EXTENDS";
/** comment = ... */
static final String COMMENT = "COMMENT";
private final EntityFactoryImpl factory; // the factory
private final SourceInfo sourceInfo; // the source info
private String name; // the entities name
private int classId; // the class id
private String tableName; // the table name
private String schemaName; // the schema name
private String tableNameWithoutSchema; // schema relative table name
private String tableAlias; // the table alias
private Integrity integrity; // referential integrity
private InheritanceType inheritanceType; // the inheritance type
private String superEntityName; // the name of the extended super class
private Entity superEntity; // the super entity
private int inheritanceLevel; // number of super entities
private final List subEntities; // the sub entities
private final EntityOptionsImpl options; // options
private final List attributes; // the attributes
private Attribute contextIdAttribute; // attribute holding the context id, null if none
private List uniqueDomainKey; // the unique domain key attributes
private List sorting; // the default sorting
private final List relations; // the relations
private final List referencingRelations; // the referencing relations from other entities
private final List indexes; // the indexes
private final Set> compositePaths; // paths of composite relations to this entity
private final List deepReferencesToComponents; // deep references to components of this root entity
private final List deepReferences; // deep references to this entity
private boolean deeplyReferenced; // true if this or any component is deeply referenced
private boolean modelRoot; // is root entity according to model
private boolean modelRootId; // provides a root-ID according to model
private boolean modelRootClassId; // provides a root-class-ID according to model
/**
* Creates an entity.
*
* @param factory the factory to create entity options
* @param sourceInfo the source information
*/
public EntityImpl(EntityFactoryImpl factory, SourceInfo sourceInfo) {
this.factory = factory;
this.sourceInfo = sourceInfo;
integrity = Integrity.NONE;
inheritanceType = InheritanceType.NONE;
options = factory.createEntityOptions(this, sourceInfo);
attributes = new ArrayList<>();
relations = new ArrayList<>();
referencingRelations = new ArrayList<>();
subEntities = new ArrayList<>();
compositePaths = new HashSet<>();
deepReferences = new ArrayList<>();
deepReferencesToComponents = new ArrayList<>();
indexes = new ArrayList<>();
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.name);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final EntityImpl other = (EntityImpl) obj;
return Objects.equals(this.name, other.name);
}
@Override
public int compareTo(EntityImpl o) {
return Compare.compare(name, o.name);
}
/**
* Parses a configuration line.
*
* @param line the configuation line
* @return true if known configuration processed
* @throws ModelException if parsing failed
*/
public boolean parseConfiguration(ConfigurationLine line) throws ModelException {
boolean parsed = true;
switch (line.getKey().toUpperCase()) {
case NAME:
String str = line.getValue();
if (str.indexOf('.') >= 0) {
throw line.createModelException("entity name must not contain package name");
}
if (!BasicStringHelper.isValidJavaClassName(str)) {
throw line.createModelException("'" + str + "' is not a valid Java class name");
}
setName(str);
break;
case ID:
String idStr = line.getValue();
setClassId(Integer.parseInt(idStr));
break;
case TABLE:
setTableName(line.getValue());
break;
case ALIAS:
setTableAlias(line.getValue());
break;
case INTEGRITY:
try {
setIntegrity(Integrity.valueOf(line.getValue().toUpperCase()));
}
catch (IllegalArgumentException ex) {
throw line.createModelException("illegal integrity level: " + line.getValue());
}
break;
case INHERITANCE:
try {
setInheritanceType(InheritanceType.valueOf(line.getValue().toUpperCase()));
}
catch (IllegalArgumentException ex) {
throw line.createModelException("illegal inhertitance type: " + line.getValue());
}
break;
case EXTENDS:
setSuperEntityName(line.getValue());
break;
case COMMENT:
getOptions().setComment(line.getValue());
break;
default:
parsed = false;
}
return parsed;
}
@Override
public String getName() {
return name;
}
/**
* Sets the entity's name.
*
* @param name the name
*/
public void setName(String name) {
this.name = name;
}
@Override
public int getClassId() {
return classId;
}
/**
* Sets the entity id.
*
* @param classId the id
*/
public void setClassId(int classId) {
this.classId = classId;
}
@Override
public String getTableName() {
return tableName;
}
@Override
public String getSchemaName() {
return schemaName;
}
@Override
public String getTableNameWithoutSchema() {
return tableNameWithoutSchema;
}
@Override
public String getTableAlias() {
return tableAlias;
}
/**
* Sets the tablename.
*
* @param tableName the tablename
*/
public void setTableName(String tableName) {
if (tableName == null) {
this.tableName = null;
schemaName = null;
tableNameWithoutSchema = null;
}
else {
this.tableName = tableName.toLowerCase();
int ndx = tableName.indexOf('.');
if (ndx > 0) {
schemaName = tableName.substring(0, ndx);
tableNameWithoutSchema = tableName.substring(ndx + 1);
}
else {
tableNameWithoutSchema = this.tableName;
}
}
}
/**
* Sets the table alias.
*
* @param tableAlias the alias
*/
public void setTableAlias(String tableAlias) {
this.tableAlias = tableAlias;
}
@Override
public Integrity getIntegrity() {
return integrity;
}
@Override
public InheritanceType getInheritanceType() {
return inheritanceType;
}
@Override
public InheritanceType getHierarchyInheritanceType() {
return superEntity == null ? inheritanceType : superEntity.getInheritanceType();
}
@Override
public String getSuperEntityName() {
return superEntityName;
}
@Override
public Entity getSuperEntity() {
return superEntity;
}
@Override
public List getSuperEntities() {
List superEntities = new ArrayList<>();
Entity entity = this;
while (entity.getSuperEntity() != null) {
superEntities.add(entity.getSuperEntity());
entity = entity.getSuperEntity();
}
return superEntities;
}
@Override
public Entity getTopSuperEntity() {
Entity entity = this;
while (entity.getSuperEntity() != null) {
entity = entity.getSuperEntity();
}
return entity;
}
@Override
public List getInheritanceChain(Entity childEntity) throws ModelException {
List chain = new ArrayList<>();
Entity entity = childEntity;
while (entity != null) {
chain.add(0, entity);
if (entity == this) {
break;
}
entity = entity.getSuperEntity();
}
if (chain.isEmpty() || chain.get(0) != this) {
throw new ModelException(this + " is not a superclass of " + childEntity);
}
return chain;
}
@Override
public int getInheritanceLevel() {
return inheritanceLevel;
}
@Override
public List getSubEntities() {
return subEntities;
}
@Override
public List getAllSubEntities() {
List childs = new ArrayList<>();
collectSubEntities(childs, this);
return childs;
}
@Override
public List getLeafEntities() {
List leafs = new ArrayList<>();
collectLeafEntities(leafs, this);
return leafs;
}
/**
* Recursivly collects the leaf childs.
*
* @param leafs the list if leafs
* @param entity the current entity to analyze
*/
protected void collectLeafEntities(List leafs, Entity entity) {
if (entity.isAbstract()) {
for (Entity child: entity.getSubEntities()) {
collectLeafEntities(leafs, child);
}
}
else {
leafs.add(entity);
}
}
/**
* Recursivly collects all sub entities.
*
* @param subEntities the list of collected sub entities
* @param entity the current entity to analyze
*/
protected void collectSubEntities(List subEntities, Entity entity) {
for (Entity sub: entity.getSubEntities()) {
subEntities.add(sub);
collectSubEntities(subEntities, sub);
}
}
@Override
public Set getAssociatedEntities() {
Set associates = new HashSet<>();
collectAssociatedEntities(associates, this, new HashSet<>());
return associates;
}
/**
* Recursively collects the associated entities for a given entity.
*
* @param associates the set of associated entities so far
* @param entity the current entity to analyze
* @param processedEntities the already processed entities (to avoid loops)
*/
protected void collectAssociatedEntities(Set associates, Entity entity, Set processedEntities) {
if (!processedEntities.contains(entity)) {
processedEntities.add(entity);
associates.add(entity);
if (superEntity != null) {
associates.add(superEntity);
collectAssociatedEntities(associates, superEntity, processedEntities);
}
associates.addAll(getSubEntities());
for (Entity child: getSubEntities()) {
collectAssociatedEntities(associates, child, processedEntities);
}
for (Relation relation: getRelations()) {
Entity relatedEntity = relation.getEntity();
if (relatedEntity != null) { // model may be incomplete...
associates.add(relatedEntity);
collectAssociatedEntities(associates, relatedEntity, processedEntities);
}
}
for (Relation relation: getReferencingRelations()) {
Entity foreignEntity = relation.getForeignEntity();
if (foreignEntity != null) { // model may be incomplete...
associates.add(foreignEntity);
collectAssociatedEntities(associates, foreignEntity, processedEntities);
}
}
}
}
/**
* Sets the integrity.
*
* @param integrity the integrity
*/
public void setIntegrity(Integrity integrity) {
if (integrity == null) {
throw new IllegalArgumentException("integrity cannot be set to null");
}
this.integrity = integrity;
}
/**
* Sets the inheritance type.
*
* @param inheritanceType the inheritance type
*/
public void setInheritanceType(InheritanceType inheritanceType) {
if (inheritanceType == null) {
throw new IllegalArgumentException("inheritance type cannot be set to null");
}
this.inheritanceType = inheritanceType;
}
/**
* Sets the inheritance level.
*
* @param inheritanceLevel the inheritance level
*/
public void setInheritanceLevel(int inheritanceLevel) {
this.inheritanceLevel = inheritanceLevel;
}
/**
* Sets the name of the super entity.
*
* @param superEntityName the super entity
*/
public void setSuperEntityName(String superEntityName) {
this.superEntityName = superEntityName;
}
/**
* Sets the super entity.
*
* @param superEntity the super entity
*/
public void setSuperEntity(Entity superEntity) {
this.superEntity = superEntity;
}
/**
* Sets the context id attribute.
*
* @param contextIdAttribute the attribute providing the context ID
*/
public void setContextIdAttribute(Attribute contextIdAttribute) {
this.contextIdAttribute = contextIdAttribute;
}
/**
* Sets the default sorting.
*
* @param sorting the sorting, null if none
*/
public void setSorting(List sorting) {
this.sorting = sorting;
}
@Override
public EntityOptionsImpl getOptions() {
return options;
}
@Override
public List getAttributes() {
return attributes;
}
/**
* Returns whether this entity is a root-entity according to model.
*
* @return true if root entity
*/
@Override
public boolean isRootEntityAccordingToModel() {
return modelRoot;
}
/**
* Sets whether this entity is a root-entity according to model.
*
* @param modelRoot true if root entity
*/
public void setRootEntityAccordingToModel(boolean modelRoot) {
this.modelRoot = modelRoot;
}
/**
* Returns whether this entity should provide a root class id according to model.
*
* @return true if should provide a root class id
*/
@Override
public boolean isProvidingRootClassIdAccordingToModel() {
return modelRootClassId;
}
/**
* Sets whether this entity should provide a root class id according to model.
*
* @param modelRootClassId true if should provide a root class id
*/
public void setProvidingRootClassIdAccordingToModel(boolean modelRootClassId) {
this.modelRootClassId = modelRootClassId;
}
/**
* Returns whether this entity should provide a root id according to model.
*
* @return true if should provide a root id
*/
@Override
public boolean isProvidingRootIdAccordingToModel() {
return modelRootId;
}
/**
* Sets whether this entity should provide a root id according to model.
*
* @param modelRootId true if should provide a root id
*/
public void setProvidingRootIdAccordingToModel(boolean modelRootId) {
this.modelRootId = modelRootId;
}
@Override
public List getInheritedAttributes() {
List inheritedAttributes = new ArrayList<>();
Entity se = getSuperEntity();
while (se != null) {
inheritedAttributes.addAll(0, se.getAttributes());
se = se.getSuperEntity();
}
return inheritedAttributes;
}
@Override
public List getSubEntityAttributes() {
List subAttributes = new ArrayList<>();
for (Entity sub: getAllSubEntities()) {
for (Attribute attribute: sub.getAttributes()) {
if (!attribute.getJavaName().equals(Constants.AN_ID) &&
!attribute.getJavaName().equals(Constants.AN_SERIAL)) {
subAttributes.add(attribute);
}
}
}
return subAttributes;
}
@Override
public List getAttributesIncludingInherited() {
List allAttributes = new ArrayList<>(getInheritedAttributes());
allAttributes.addAll(attributes);
allAttributes = moveIdSerialToEnd(allAttributes);
return allAttributes;
}
@Override
public List getAttributesIncludingSubEntities() {
List allAttributes = new ArrayList<>(attributes);
allAttributes.addAll(getSubEntityAttributes());
allAttributes = moveIdSerialToEnd(allAttributes);
return allAttributes;
}
@Override
public List getAllAttributes() {
List allAttributes = new ArrayList<>(getInheritedAttributes());
allAttributes.addAll(attributes);
allAttributes.addAll(getSubEntityAttributes());
allAttributes = moveIdSerialToEnd(allAttributes);
return allAttributes;
}
@Override
public List getTableAttributes() {
InheritanceType ihType = getHierarchyInheritanceType();
List tableAttributes;
if (ihType.isMappingToOwnTable()) {
tableAttributes = new ArrayList<>(attributes);
if (getSuperEntity() != null) {
// always add the ID for subclasses in MULTI inheritance
tableAttributes.add(getAttributeByJavaName(Constants.AN_ID, true));
}
}
else if (ihType.isMappingToSuperTable()) {
tableAttributes = new ArrayList<>();
if (isRootOfInheritanceHierarchy()) {
tableAttributes.addAll(attributes);
for (Entity child: getAllSubEntities()) {
tableAttributes.addAll(child.getAttributes());
}
tableAttributes = moveIdSerialToEnd(tableAttributes);
}
}
else {
tableAttributes = getAttributesIncludingInherited();
}
return tableAttributes;
}
@Override
public List getMappedAttributes() {
List mappedAttributes;
if (isAbstract()) {
if (inheritanceType.isMappingToOwnTable()) {
// MULTI
mappedAttributes = attributes;
}
else if (inheritanceType.isMappingToSuperTable()) {
// SINGLE: strip id and serial. It's mapped by the leafs
mappedAttributes = removeIdSerial(attributes);
}
else {
// PLAIN
mappedAttributes = new ArrayList<>();
}
}
else { // leaf
InheritanceType ihType = getHierarchyInheritanceType();
if (ihType.isMappingToOwnTable()) {
// MULTI
mappedAttributes = attributes;
}
else if (ihType.isMappingToSuperTable()) {
// SINGLE: get id and serial from top of hierarchy
Entity top = getTopSuperEntity();
mappedAttributes = appendIdSerial(top, attributes);
}
else if (ihType.isMappingToNoTable()) {
// PLAIN
mappedAttributes = getAttributesIncludingInherited();
}
else { // NONE
mappedAttributes = attributes;
}
}
return mappedAttributes;
}
/**
* Moved id and serial to the end of a new created attribute list.
*
* @param attributes the attribute list
* @return the new filtered attribute list
*/
protected List moveIdSerialToEnd(List attributes) {
Attribute idAttribute = null;
Attribute serialAttribute = null;
List filteredList = new ArrayList<>();
for (Attribute attribute: attributes) {
if (Constants.CN_ID.equals(attribute.getJavaName())) {
idAttribute = attribute;
continue;
}
if (Constants.CN_SERIAL.equals(attribute.getJavaName())) {
serialAttribute = attribute;
continue;
}
filteredList.add(attribute);
}
if (idAttribute != null) {
filteredList.add(idAttribute);
}
if (serialAttribute != null) {
filteredList.add(serialAttribute);
}
return filteredList;
}
/**
* Removes id and serial from the list of attributes.
*
* @param attributes the attribute list
* @return the new filtered attribute list
*/
protected List removeIdSerial(List attributes) {
List filteredList = new ArrayList<>();
for (Attribute attribute: attributes) {
if (!Constants.CN_ID.equals(attribute.getJavaName()) &&
!Constants.CN_SERIAL.equals(attribute.getJavaName())) {
filteredList.add(attribute);
}
}
return filteredList;
}
/**
* Appends id and serial from another entity.
*
* @param entity the entity defining id and serial
* @param attributes the attribute list
* @return the new filtered attribute list
*/
protected List appendIdSerial(Entity entity, List attributes) {
Attribute idAttribute = null;
Attribute serialAttribute = null;
for (Attribute attribute: entity.getAttributes()) {
if (Constants.CN_ID.equals(attribute.getJavaName())) {
idAttribute = attribute;
}
else if (Constants.CN_SERIAL.equals(attribute.getJavaName())) {
serialAttribute = attribute;
}
}
List filteredList = new ArrayList<>(attributes);
if (idAttribute != null) {
filteredList.add(idAttribute);
}
if (serialAttribute != null) {
filteredList.add(serialAttribute);
}
return filteredList;
}
@Override
public List getInheritedIndexes() {
List inheritedIndexes = new ArrayList<>();
Entity se = getSuperEntity();
while (se != null) {
inheritedIndexes.addAll(0, se.getIndexes());
se = se.getSuperEntity();
}
return inheritedIndexes;
}
@Override
public List getIndexesIncludingInherited() {
List allIndexes = new ArrayList<>(getInheritedIndexes());
allIndexes.addAll(indexes);
return allIndexes;
}
@Override
public List getSubEntityIndexes() {
List subIndexes = new ArrayList<>();
for (Entity sub: getSubEntities()) {
subIndexes.addAll(sub.getIndexes());
}
return subIndexes;
}
@Override
public List getIndexesIncludingSubEntities() {
List allIndexes = new ArrayList<>(indexes);
allIndexes.addAll(getSubEntityIndexes());
return allIndexes;
}
@Override
public List getAllIndexes() {
List allIndexes = new ArrayList<>(getInheritedIndexes());
allIndexes.addAll(indexes);
allIndexes.addAll(getSubEntityIndexes());
return allIndexes;
}
@Override
public List getTableIndexes() {
InheritanceType ihType = getHierarchyInheritanceType();
List tableIndexes;
if (ihType.isMappingToOwnTable()) {
tableIndexes = indexes;
}
else if (ihType.isMappingToSuperTable()) {
tableIndexes = new ArrayList<>();
if (isRootOfInheritanceHierarchy()) {
tableIndexes.addAll(indexes);
for (Entity child: getAllSubEntities()) {
tableIndexes.addAll(child.getIndexes());
}
}
}
else {
tableIndexes = getIndexesIncludingInherited();
}
return tableIndexes;
}
@Override
public List getInheritedRelations() {
List allRelations = new ArrayList<>();
Entity se = getSuperEntity();
while (se != null) {
allRelations.addAll(0, se.getRelations());
se = se.getSuperEntity();
}
return allRelations;
}
@Override
public List getSubEntityRelations() {
List allRelations = new ArrayList<>();
for (Entity sub: getAllSubEntities()) {
allRelations.addAll(sub.getRelations());
}
return allRelations;
}
@Override
public List getRelationsIncludingInherited() {
List allRelations = new ArrayList<>(getInheritedRelations());
allRelations.addAll(relations);
return allRelations;
}
@Override
public List getRelationsIncludingSubEntities() {
List allRelations = new ArrayList<>(relations);
allRelations.addAll(getSubEntityRelations());
return allRelations;
}
@Override
public List getAllRelations() {
List allRelations = getRelationsIncludingInherited();
allRelations.addAll(getSubEntityRelations());
return allRelations;
}
@Override
public List getTableRelations() {
InheritanceType ihType = getHierarchyInheritanceType();
List tableRelations;
if (ihType.isMappingToOwnTable()) {
tableRelations = relations;
}
else if (ihType.isMappingToSuperTable()) {
tableRelations = new ArrayList<>();
if (isRootOfInheritanceHierarchy()) {
tableRelations.addAll(relations);
for (Entity sub: getAllSubEntities()) {
tableRelations.addAll(sub.getRelations());
}
}
}
else {
tableRelations = getRelationsIncludingInherited();
}
return tableRelations;
}
@Override
public Set> getCompositePaths() {
return compositePaths;
}
@Override
public Set getComponents() {
Set components = new TreeSet<>();
for (Relation relation: getRelations()) {
if (relation.isComposite()) {
components.add(relation.getForeignEntity());
}
}
return components;
}
@Override
public Set getComponentsIncludingInherited() {
Set components = new TreeSet<>();
for (Relation relation: getRelationsIncludingInherited()) {
if (relation.isComposite()) {
components.add(relation.getForeignEntity());
}
}
return components;
}
@Override
public Set getAllComponents() {
Set components = new TreeSet<>();
for (Relation relation: getRelationsIncludingInherited()) {
if (relation.isComposite()) {
Entity component = relation.getForeignEntity();
components.add(component);
components.addAll(component.getComponentsIncludingInherited());
}
}
return components;
}
@Override
public boolean isDeeplyReferenced() {
return deeplyReferenced;
}
public void setDeeplyReferenced(boolean deeplyReferenced) {
this.deeplyReferenced = deeplyReferenced;
}
@Override
public List getDeepReferences() {
return deepReferences;
}
@Override
public List getDeepReferencesToComponents() {
return deepReferencesToComponents;
}
@Override
public List getDeeplyReferencedComponents() {
List deepRelations = new ArrayList<>();
for (Relation relation : relations) {
if (relation.isComposite()) {
Entity component = relation.getForeignEntity();
if (component.isDeeplyReferenced()) {
deepRelations.add(relation);
}
}
}
return deepRelations;
}
@Override
public Attribute getAttributeByJavaName(String javaName, boolean all) {
if (javaName != null) {
Entity entity = this;
while (entity != null) {
for (Attribute attribute: entity.getAttributes()) {
if (javaName.equalsIgnoreCase(attribute.getJavaName())) {
return attribute;
}
}
if (all) {
entity = entity.getSuperEntity();
}
else {
break;
}
}
}
return null;
}
@Override
public Attribute getAttributeByColumnName(String columnName, boolean all) {
if (columnName != null) {
columnName = columnName.toLowerCase();
Entity entity = this;
while (entity != null) {
for (Attribute attribute: entity.getAttributes()) {
if (columnName.equals(attribute.getColumnName())) {
return attribute;
}
}
if (all) {
entity = entity.getSuperEntity();
}
else {
break;
}
}
}
return null;
}
@Override
public Attribute getContextIdAttribute() {
return contextIdAttribute;
}
@Override
public List getUniqueDomainKey() {
if (uniqueDomainKey == null) {
uniqueDomainKey = new ArrayList<>();
if (isRootEntityAccordingToModel()) {
getUniqueDomainKeyImpl(uniqueDomainKey, this);
}
}
return uniqueDomainKey;
}
/**
* Adds the unique domain keys recursively for given entity to the list.
*
* @param uniqueDomainKeys the unique domain key attributes
* @param entity the entity to inspect
*/
protected void getUniqueDomainKeyImpl(List uniqueDomainKeys, Entity entity) {
for (Attribute attribute : entity.getAttributesIncludingInherited()) {
if (attribute.getOptions().isDomainKey()) {
uniqueDomainKeys.add(attribute);
}
}
for (Entity component: entity.getComponentsIncludingInherited()) {
if (!component.isRootEntityAccordingToModel()) { // stop at sub-roots!
getUniqueDomainKeyImpl(uniqueDomainKeys, component);
}
}
}
@Override
public List getSorting() {
return sorting;
}
@Override
public List getIndexes() {
return indexes;
}
@Override
public Index getIndex(String name, boolean all) {
if (name != null) {
Entity entity = this;
while (entity != null) {
for (Index index: entity.getIndexes()) {
if (name.equalsIgnoreCase(index.getName())) {
return index;
}
}
if (all) {
entity = entity.getSuperEntity();
}
else {
break;
}
}
}
return null;
}
@Override
public List getRelations() {
return relations;
}
@Override
public List getReferencingRelations() {
return referencingRelations;
}
@Override
public List getInheritedReferencingRelations() {
List inheritedReferencingRelations = new ArrayList<>();
Entity se = getSuperEntity();
while (se != null) {
inheritedReferencingRelations.addAll(0, se.getReferencingRelations());
se = se.getSuperEntity();
}
return inheritedReferencingRelations;
}
@Override
public List getReferencingRelationsIncludingInherited() {
List allRelations = new ArrayList<>(getInheritedReferencingRelations());
allRelations.addAll(getReferencingRelations());
return allRelations;
}
@Override
public List getSubEntityReferencingRelations() {
List subReferencingRelations = new ArrayList<>();
for (Entity sub: getAllSubEntities()) {
subReferencingRelations.addAll(sub.getReferencingRelations());
}
return subReferencingRelations;
}
@Override
public List getReferencingRelationsIncludingSubEntities() {
List allRelations = new ArrayList<>(getReferencingRelations());
allRelations.addAll(getSubEntityReferencingRelations());
return allRelations;
}
@Override
public List getAllReferencingRelations() {
List allRelations = new ArrayList<>(getReferencingRelationsIncludingInherited());
allRelations.addAll(getSubEntityReferencingRelations());
return allRelations;
}
@Override
public Relation getRelation(String name, boolean all) {
if (name != null) {
Entity entity = this;
while (entity != null) {
for (Relation relation: entity.getRelations()) {
if (name.equalsIgnoreCase(relation.getName())) {
return relation;
}
}
if (all) {
entity = entity.getSuperEntity();
}
else {
break;
}
}
}
return null;
}
/**
* Validates the entity without relation dependent settings.
*
* @throws ModelException if validation failed
*/
public void validate() throws ModelException {
if (BasicStringHelper.isAllWhitespace(getName())) {
throw new ModelException("configuration 'name = ...' missing", this);
}
if (!isAbstract()) {
if (getClassId() == 0) {
throw new ModelException("configuration 'id = ...' missing", this);
}
}
else {
if (getClassId() != 0) {
throw new ModelException("configuration 'id = ...' not allowed", this);
}
}
getOptions().validate();
if (getOptions().isRootEntity()) {
if (getSuperEntityName() != null) {
throw new ModelException("[ROOT] option cannot be applied to subclasses", this);
}
if (getOptions().isRootIdProvided()) {
throw new ModelException("root entities cannot provide a rootid column", this);
}
if (getOptions().isRootClassIdProvided()) {
throw new ModelException("root entities cannot provide a rootclassid column", this);
}
}
Set javaNames = new HashSet<>();
Set columnNames = new HashSet<>();
for (Attribute attribute: getAttributes()) {
attribute.validate();
if (!javaNames.add(attribute.getJavaName())) {
throw new ModelException("duplicate Java name '" + attribute.getJavaName() + "'", this);
}
if (!columnNames.add(attribute.getColumnName())) {
throw new ModelException("duplicate column name '" + attribute.getColumnName() + "'", this);
}
}
Set indexNames = new HashSet<>();
for (Index index: getIndexes()) {
index.validate();
if (!indexNames.add(index.getName())) {
throw new ModelException("duplicate index '" + index.getName() + "'", this);
}
}
Set relationNames = new HashSet<>();
for (Relation relation: getRelations()) {
relation.validate();
if (!relationNames.add(relation.getName())) {
throw new ModelException("duplicate relation '" + relation.getName() + "'", this);
}
}
}
/**
* Validates the relation dependent settings.
* Assumes {@link ModelImpl#updateRelations} applied successfully.
*
* @throws ModelException if validation failed
*/
public void validateRelated() throws ModelException {
if (getTableProvidingEntity() == this) {
if (BasicStringHelper.isAllWhitespace(getTableName())) {
throw new ModelException("configuration 'table = ...' missing", this);
}
if (getTableName().startsWith("_")) {
throw new ModelException("table name '" + getTableName() + "' must not start with an underscore", this);
}
for (Backend backend: factory.getBackends()) {
try {
backend.assertValidName("table name", getTableName());
backend.assertValidName("table alias", getTableAlias());
}
catch (RuntimeException rex) {
throw new ModelException(rex.getMessage(), sourceInfo, rex);
}
}
}
else {
if (!BasicStringHelper.isAllWhitespace(getTableName())) {
throw new ModelException("configuration 'table = ...' not allowed", this);
}
if (!BasicStringHelper.isAllWhitespace(getTableAlias())) {
throw new ModelException("configuration 'alias = ...' not allowed", this);
}
}
if (isRootOfInheritanceHierarchy() && inheritanceType.isMappingToSuperTable()) {
// set attributes to nullable (except the ones in root)
for (Entity sub: getAllSubEntities()) {
for (Attribute attribute: sub.getAttributes()) {
((AttributeImpl) attribute).setNullable(true);
}
}
}
if (getIntegrity().isCompositesCheckedByDatabase()) {
// either all composite relations must be cascaded or none, not mixed!
if (isDeletionCascaded() == null) {
throw new ModelException(getIntegrity() +
" integrity requires all composite relations to be either cascaded or non-cascaded", this);
}
}
}
@Override
public String sqlCreateTable(Backend backend) throws ModelException {
StringBuilder buf = new StringBuilder();
buf.append(backend.sqlCreateTableIntro(getTableName(), getOptions().getComment()));
List tableAttributes = getTableAttributes();
int attributeNum = tableAttributes.size();
int attributeCount = 1;
for (Attribute attribute: tableAttributes) {
if (!attribute.getOptions().isDerived()) {
DataType dataType = attribute.getDataType();
if (dataType == DataType.APPLICATION) {
dataType = attribute.getInnerType();
}
int multiColumnIndex = 1;
int multiColumnSize = dataType.getSqlTypes().length;
for (DataType.SqlTypeWithPostfix sp: dataType.getSqlTypesWithPostfix()) {
buf.append(" ");
String columnName = attribute.getColumnName() + sp.getPostfix();
int size = attribute.getSizeWithDefault();
int scale = attribute.getScaleWithDefault();
Object defaultValue = attribute.getOptions().getDefaultValue();
String comment = attribute.getOptions().getComment();
if (multiColumnIndex > 1) {
comment = null;
if (defaultValue != null) {
defaultValue = sp.getSqlType().getDefaultValue();
}
}
if (dataType.isScaleInSecondColumn()) {
if (multiColumnIndex == 2) {
size = 0;
}
scale = 0;
}
buf.append(backend.sqlCreateColumn(
columnName, comment, sp.getSqlType(), size, scale,
attribute.isNullable(), defaultValue,
attribute.getJavaName().equals(Constants.AN_ID),
attributeCount < attributeNum || multiColumnIndex < multiColumnSize));
multiColumnIndex++;
}
attributeCount++;
}
}
buf.append(backend.sqlCreateTableClosing(getTableName(), getOptions().getComment()));
buf.append(backend.sqlCreateTableComment(getTableName(), getOptions().getComment()));
for (Attribute attribute: tableAttributes) {
if (!attribute.getOptions().isDerived()) {
buf.append(backend.sqlCreateColumnComment(getTableName(), attribute.getColumnName(), attribute.getOptions().getComment()));
}
}
return buf.toString();
}
@Override
public boolean isComposite() {
for (Relation relation: getRelationsIncludingSubEntities()) {
if (relation.isComposite()) {
return true;
}
}
return false;
}
@Override
public boolean isAbstract() {
return inheritanceType.isAbstractClass();
}
@Override
public boolean isTracked() {
return getOptions().getTrackType().isTracked();
}
@Override
public Boolean isDeletionCascaded() {
Boolean cascaded = null;
for (Relation relation: getRelations()) {
if (relation.isComposite()) {
if (cascaded == null) {
cascaded = relation.isDeletionCascaded();
}
else if (cascaded != relation.isDeletionCascaded()) {
return null; // mixed
}
}
}
if (cascaded == null) {
// no composite relation at all
cascaded = false;
}
return cascaded;
}
@Override
public boolean isRootOfInheritanceHierarchy() {
return superEntityName == null && inheritanceType != InheritanceType.NONE;
}
@Override
public Set getRootAttributes() {
Set rootAttributes = new HashSet<>();
for (List compositePath: compositePaths) {
Relation lastRelation = compositePath.get(compositePath.size() - 1);
if (lastRelation.getForeignAttribute() != null) {
rootAttributes.add(lastRelation.getForeignAttribute());
}
}
return rootAttributes;
}
@Override
public Attribute getRootAttribute() {
Set rootAttributes = getRootAttributes();
return rootAttributes.size() == 1 ? rootAttributes.iterator().next() : null;
}
@Override
public Set getRootEntities() {
Set rootEntities = new HashSet<>();
for (List compositePath: compositePaths) {
Relation firstRelation = compositePath.get(0);
rootEntities.add(firstRelation.getEntity());
}
return rootEntities;
}
@Override
public Entity getRootEntity() {
Set rootEntities = getRootEntities();
if (rootEntities.size() == 1) {
Entity rootEntity = rootEntities.iterator().next();
if (!rootEntity.isAbstract()) {
return rootEntity;
}
}
return null;
}
@Override
public Entity getTableProvidingEntity() {
InheritanceType ihType = getHierarchyInheritanceType();
if (ihType.isMappingToOwnTable()) {
return this;
}
if (ihType.isMappingToSuperTable()) {
return getTopSuperEntity();
}
if (inheritanceType.isMappingToOwnTable()) {
return this;
}
return null;
}
@Override
public String toString() {
return getName();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy