Java tutorial
/* * Copyright 2015 JAXIO http://www.jaxio.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaxio.celerio.model; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.jaxio.celerio.Config; import com.jaxio.celerio.configuration.Module; import com.jaxio.celerio.configuration.convention.CollectionType; import com.jaxio.celerio.configuration.entity.EntityConfig; import com.jaxio.celerio.configuration.entity.ImplementsInterface; import com.jaxio.celerio.configuration.entity.Inheritance; import com.jaxio.celerio.convention.ClassType; import com.jaxio.celerio.factory.RelationCollisionUtil; import com.jaxio.celerio.factory.conventions.AuditEntityConvention; import com.jaxio.celerio.factory.conventions.AuditLogConvention; import com.jaxio.celerio.factory.conventions.SavedSearchConvention; import com.jaxio.celerio.model.support.*; import com.jaxio.celerio.model.support.EntityPredicates.ExcludeEntity; import com.jaxio.celerio.model.support.account.AccountAttributes; import com.jaxio.celerio.model.support.account.RoleAttributes; import com.jaxio.celerio.model.support.account.SavedSearchAttributes; import com.jaxio.celerio.support.Namer; import com.jaxio.celerio.util.Hierarchical; import com.jaxio.celerio.util.Labels; import com.jaxio.celerio.util.Named; import com.jaxio.celerio.util.support.CurrentAndFlatListHolder; import com.jaxio.celerio.util.support.HierarchicalSupport; import com.jaxio.celerio.util.support.ListGetter; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import javax.persistence.InheritanceType; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import static com.google.common.base.Predicates.and; import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Sets.newTreeSet; import static com.jaxio.celerio.configuration.database.support.SqlUtil.escapeSql; import static com.jaxio.celerio.model.support.AttributePredicates.*; import static com.jaxio.celerio.model.support.AttributePredicates.SIMPLE; import static com.jaxio.celerio.model.support.EntityListGetters.*; import static com.jaxio.celerio.model.support.EntityPredicates.HAS_FILE_ATTRIBUTES; import static com.jaxio.celerio.model.support.RelationPredicates.*; import static com.jaxio.celerio.model.support.SuffixPrefixPredicates.IS_BINARY_SUFFIX; import static com.jaxio.celerio.model.support.UniquePredicates.COMPOSITE_UNIQUE; import static com.jaxio.celerio.model.support.UniquePredicates.SIMPLE_UNIQUE; import static com.jaxio.celerio.util.FallBackUtil.fallBack; import static com.jaxio.celerio.util.MiscUtil.toReadableLabel; import static java.util.Collections.unmodifiableList; import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; /** * JPA Entity meta information. */ @Component @Scope(SCOPE_PROTOTYPE) @Slf4j @Getter public class Entity implements Hierarchical<Entity>, Named, Map<String, Object> { @Autowired private Config config; @Autowired private RelationCollisionUtil collisionUtil; @Setter private boolean virtual; @Setter private boolean view; @Setter private boolean manyToManyJoinEntity; private Entity parent; private EntityConfig entityConfig; // account / role support for spring security @Setter private AccountAttributes accountAttributes; @Setter private RoleAttributes roleAttributes; // ----------------------------------- // Namers // ----------------------------------- // Used from velocity templates private Namer model = newClassNamer(ClassType.model); private Namer controllerWithPathVariable = newClassNamer(ClassType.controllerWithPathVariable); private Namer dao = newClassNamer(ClassType.dao); private Namer converter = newClassNamer(ClassType.converter); private Namer formatter = newClassNamer(ClassType.formatter); private Namer formService = newClassNamer(ClassType.formService); private Namer validator = newClassNamer(ClassType.validator); private Namer formValidator = newClassNamer(ClassType.formValidator); private Namer repository = newClassNamer(ClassType.repository); private Namer repositorySupport = newClassNamer(ClassType.repositorySupport); // service is like repository... just a matter of taste. private Namer service = newClassNamer(ClassType.service); private Namer serviceImpl = newClassNamer(ClassType.serviceImpl); private Namer serviceSupport = newClassNamer(ClassType.serviceSupport); private Namer entityForm = newClassNamer(ClassType.entityForm); private Namer context = newClassNamer(ClassType.context); private Namer modelGenerator = newClassNamer(ClassType.modelGenerator); private Namer searchController = newClassNamer(ClassType.searchController); private Namer webSupport = newClassNamer(ClassType.webSupport); private Namer webModel = newClassNamer(ClassType.webModel); private Namer webModelConverter = newClassNamer(ClassType.webModelConverter); private Namer webModelItems = newClassNamer(ClassType.webModelItems); private Namer webPermission = newClassNamer(ClassType.webPermission); private Namer seleniumEditPage = new DomainSubpackageClassNamer(this, ClassType.seleniumEditPage); private Namer seleniumSearchPage = new DomainSubpackageClassNamer(this, ClassType.seleniumSearchPage); private Namer printer = newClassNamer(ClassType.printer); @Setter private PrimaryKey primaryKey; // base attributes, the getters return unmodifiableList to make sure we go through the instance to manipulate them private List<Entity> children = newArrayList(); private List<Attribute> currentAttributes = newArrayList(); private Map<String, Attribute> currentAttributesByColumnFullName = newHashMap(); private Map<String, Attribute> currentAttributesByName = newHashMap(); // ----------------------------------- // Unique // ----------------------------------- private List<Unique> currentUniques = newArrayList(); private EntityUniques uniques = newEntityUniques(); private EntityUniques simpleUniques = newEntityUniques(SIMPLE_UNIQUE); private EntityUniques compositeUniques = newEntityUniques(COMPOSITE_UNIQUE); // ----------------------------------- // Relations // ----------------------------------- private List<Relation> currentRelations = newArrayList(); private EntityRelations relations = newEntityRelations(); private EntityRelations relationsExceptNN = newEntityRelations(NOT_MANY_TO_MANY); private EntityRelations collectionRelations = newEntityRelations(COLLECTION); private EntityRelations oneToMany = newEntityRelations(ONE_TO_MANY); private EntityRelations oneToVirtualOne = newEntityRelations(ONE_TO_VIRTUAL_ONE); private EntityRelations manyToOne = newEntityRelations(MANY_TO_ONE); private EntityRelations xToOne = newEntityRelations(X_TO_ONE); private EntityRelations forwardXToOne = newEntityRelations(FORWARD_X_TO_ONE); private EntityRelations nonSimpleXToOne = newEntityRelations(NON_SIMPLE_X_TO_ONE); private EntityRelations compositeXToOne = newEntityRelations(COMPOSITE_X_TO_ONE); private EntityRelations unidirectionalXToOne = newEntityRelations(UNIDIRECTIONAL_X_TO_ONE); private EntityRelations bidirectionalXToOne = newEntityRelations(BIDIRECTIONAL_X_TO_ONE); private EntityRelations intermediateXToOne = newEntityRelations(INTERMEDIATE_X_TO_ONE); private EntityRelations oneToOne = newEntityRelations(ONE_TO_ONE); private EntityRelations inverseOneToOne = newEntityRelations(SIMPLE_INVERSE_ONE_TO_ONE); private EntityRelations manyToMany = newEntityRelations(MANY_TO_MANY); private EntityRelations unidirectionalManyToMany = newEntityRelations(UNIDIRECTIONAL_MANY_TO_MANY); private EntityRelations bidirectionalManyToMany = newEntityRelations(BIDIRECTIONAL_MANY_TO_MANY); private EntityRelations xToMany = newEntityRelations(X_TO_MANY); private EntityRelations composite = newEntityRelations(COMPOSITE); private EntityRelations simpleRelations = newEntityRelations(RelationPredicates.SIMPLE); private EntityRelations inverseRelations = newEntityRelations(RELATION_IS_INVERSE); private EntityRelations formInputFieldRelations = newEntityRelations(FORM_INPUT_FIELD_RELATION); // ----------------------------------- // Hierarchy // ----------------------------------- private HierarchicalSupport<Entity> hierarchicalSupport = new HierarchicalSupport<Entity>(this); private CurrentAndFlatListHolder<Entity, Entity> hierarchy = new CurrentAndFlatListHolder<Entity, Entity>(this, HIERARCHY_ATTRIBUTES); // ----------------------------------- // Attributes // ----------------------------------- private EntityAttributes attributes = newEntityAttributes(); private EntityAttributes allAttributes = new EntityAttributes(this, ATTRIBUTES_AND_PK_ATTRIBUTES); // pk private EntityAttributes primaryKeyAttributes = new EntityAttributes(this, PK_ATTRIBUTES); private EntityAttributes nonCpkAttributes = newEntityAttributes(NOT_IN_COMPOSITE_PK); private EntityAttributes inPkAttributes = newEntityAttributes(IN_PK); private EntityAttributes simplePkAttributes = newEntityAttributes(SIMPLE_PK); private EntityAttributes notInPkAttributes = newEntityAttributes(NOT_IN_PK); private EntityAttributes cpkDateAttributes = new EntityAttributes(this, CPK_ATTRIBUTES, DATE); private EntityAttributes businessKeyByConfiguration = newEntityAttributes(BUSINESS_KEY_BY_CONFIGURATION); @Setter private List<Attribute> businessKey = newArrayList(); // set by BusinessKeyFactory. // fk private EntityAttributes inFkAttributes = newEntityAttributes(IN_FK); private EntityAttributes simpleFkAttributes = newEntityAttributes(SIMPLE_FK); // misc private EntityAttributes simpleAttributes = newEntityAttributes(SIMPLE); private EntityAttributes simpleStringAttributes = newEntityAttributes(SIMPLE, STRING); private EntityAttributes uniqueAttributes = newEntityAttributes(IS_UNIQUE, NOT_SIMPLE_PK, WITH_PUBLIC_SETTER_ACCESSIBILITY); private EntityAttributes dateAttributes = newEntityAttributes(DATE, NOT_VERSION); private EntityAttributes anyDateAttributes = newEntityAttributes(DATE); private EntityAttributes fileAttributes = newEntityAttributes(FILE); private EntityAttributes numericAttributes = newEntityAttributes(NUMERIC); private EntityAttributes localeKeyAttributes = newEntityAttributes(LOCALE_KEY); private EntityAttributes localizableAttributes = newEntityAttributes(LOCALIZABLE); private EntityAttributes enumAttributes = newEntityAttributes(ENUM); private EntityAttributes uniqueEnumAttributes = newEntityAttributes(ENUM, IS_UNIQUE); private EntityAttributes pertinentDefaultValueAttributes = newEntityAttributes(HAS_PERTINENT_DEFAULT_VALUE); private EntityAttributes labelAttributes = newEntityAttributes(IS_LABEL); private EntityAttributes printerAttributes = new EntityAttributes(this, PRINTER_ATTRIBUTES); private EntityAttributes stringPrinterAttributes = new EntityAttributes(this, STRING_PRINTER_ATTRIBUTES); private EntityAttributes indexedPrinterAttributes = new EntityAttributes(this, INDEXED_PRINTER_ATTRIBUTES); private EntityAttributes localizableDisplayStringAttributes = new EntityAttributes(this, LOCALIZABLE_TO_DISPLAY_STRING_ATTRIBUTES); private EntityAttributes versionAttributes = newEntityAttributes(VERSION); // search private EntityAttributes searchAttributes = newEntityAttributes(SEARCH_FIELD, AttributeOrder.SEARCH_FIELD); private EntityAttributes rangeableSearchAttributes = newEntityAttributes(SEARCH_FIELD, RANGEABLE_FIELD, AttributeOrder.SEARCH_FIELD); private EntityAttributes multiSelectableSearchAttributes = newEntityAttributes(SEARCH_FIELD, MULTI_SELECTABLE_FIELD, AttributeOrder.SEARCH_FIELD); private EntityAttributes hibernateSearchAttributes = newEntityAttributes(HIBERNATE_SEARCH_FIELD); private EntityAttributes searchResultAttributesConvention = newEntityAttributes(SEARCH_RESULT_CONVENTION, AttributeOrder.SEARCH_RESULT); private EntityAttributes searchResultAttributesManual = newEntityAttributes( SEARCH_RESULT_FIELD_DEFINED_MANUALLY, AttributeOrder.SEARCH_RESULT); private EntityAttributes searchResultAttributes = new EntityAttributes(this, SEARCH_RESULTS, AttributeOrder.SEARCH_RESULT); private EntityAttributes patternSearchableAttributes = newEntityAttributes(IS_PATTERN_SEARCHABLE); private EntityAttributes patternSearchableCpkAttributes = new EntityAttributes(this, CPK_ATTRIBUTES, IS_CPK_PATTERN_SEARCHABLE); private EntityAttributes withPublicSetterAccessibilityAttributes = newEntityAttributes( WITH_PUBLIC_SETTER_ACCESSIBILITY); // web private EntityAttributes visibleAttributes = newEntityAttributes(VISIBLE); private EntityAttributes sortableAttributes = newEntityAttributes(SORTABLE); private EntityAttributes defaultSortAttributes = newEntityAttributes(DEFAULT_SORT); private EntityAttributes formAttributes = newEntityAttributes(FORM_FIELD, AttributeOrder.FORM_FIELD); private EntityAttributes visibleFormAttributes = newEntityAttributes(FORM_FIELD, VISIBLE, AttributeOrder.FORM_FIELD); private EntityAttributes hiddenFormAttributes = newEntityAttributes(FORM_FIELD, HIDDEN, AttributeOrder.FORM_FIELD); // ----------------------------------- // Entities // ----------------------------------- private EntityEntity meAndRelatedEntities = newEntityEntity(); private EntityEntity relatedEntities = newEntityEntity(new ExcludeEntity(this)); public void setEntityConfig(EntityConfig config) { Assert.isNull(this.entityConfig, "entityConfig can be set only once"); Assert.notNull(config); this.entityConfig = config; } public void setParent(Entity parent) { Assert.isNull(this.parent, "parent can be set only once"); this.parent = parent; parent.addChild(this); } public boolean hasParent() { return parent != null; } public boolean hasChildren() { return children.size() > 0; } public String getParentsTrainAndSelf() { String result = ""; if (hasParent()) { for (Entity e : getParents()) { result = result + e.getName() + ":"; } } return result + getName(); } public void addAttribute(Attribute attribute) { if (currentAttributes.isEmpty()) { // let's add the entity name as it is used in certain classes and can clash with field vars. collisionUtil.addVar(getName(), getName()); } currentAttributes.add(attribute); // will prevent clash with relation var name... attribute.getColumnConfig().setFieldName(collisionUtil.getClashSafeVar(getName(), attribute.getName())); currentAttributesByName.put(attribute.getName().toUpperCase(), attribute); if (!currentAttributesByColumnFullName.containsKey(attribute.getColumnFullName().toUpperCase())) { currentAttributesByColumnFullName.put(attribute.getColumnFullName().toUpperCase(), attribute); } else { throw new IllegalStateException("The column " + attribute.getColumnFullName() + " seems to be duplicated! Please fix your database schema."); } } public void addChild(Entity child) { children.add(child); } public void addUnique(Unique unique) { currentUniques.add(unique); } public int getHierarchyLevel() { return hierarchicalSupport.getHierarchyLevel(); } //------------------------------- // Hierarchical Implementation //------------------------------- @Override public Entity getRoot() { return hierarchicalSupport.getRoot(); } @Override public boolean isRoot() { return hierarchicalSupport.isRoot(); } @Override public List<Entity> getParents() { List<Entity> result = newArrayList(); Entity current = this; while (current.hasParent()) { result.add(0, current.getParent()); current = current.getParent(); } return result; } @Override public List<Entity> getChildren() { return unmodifiableList(children); } // end Hierarchical Implementation public void addRelation(Relation relation) { if (!currentRelations.contains(relation)) { currentRelations.add(relation); } } public Attribute getAttributeByName(String name) { return currentAttributesByName.get(name.toUpperCase()); } public Attribute getAttributeByTableAndColumnName(String tableName, String columnName) { String fullName = tableName.toUpperCase() + "." + columnName.toUpperCase(); return currentAttributesByColumnFullName.get(fullName); } // ----------------------------------------------------- // Inheritance Config shortcuts // ----------------------------------------------------- public boolean hasInheritance() { return entityConfig.hasInheritance(); } public Inheritance getInheritance() { return entityConfig.getInheritance(); } public boolean hasParentEntityName() { return entityConfig.hasParentEntityName(); } public String getParentEntityName() { return entityConfig.getInheritance().getParentEntityName(); } // ----------------------------------------------------- // Config shortcuts // ----------------------------------------------------- public boolean isSkip() { return entityConfig.shouldSkip(); } @Override public String getName() { return entityConfig.getEntityName(); } public boolean hasTableName() { return isNotBlank(entityConfig.getTableName()); } public String getTableName() { return entityConfig.getTableName(); } public String getTableNameEscaped() { return escapeSql(getTableName()); } @Override public String toString() { return getName(); } public boolean hasCompositePk() { return primaryKey.isComposite(); } public boolean hasSimplePk() { return primaryKey.isSimple(); } public boolean hasDatePk() { return primaryKey.isSimple() && getPrimaryKey().getAttribute().isDate(); } public boolean hasPrimaryKey() { return hasCompositePk() || hasSimplePk(); } public List<Attribute> getCurrentAttributes() { return unmodifiableList(currentAttributes); } public List<Relation> getCurrentRelations() { return unmodifiableList(currentRelations); } public List<Unique> getCurrentUniques() { return unmodifiableList(currentUniques); } // ----------------------------------------------------- // Tables // ----------------------------------------------------- public Set<String> getTableNamesInvolvedInEntity() { Set<String> tableNames = newTreeSet(); for (Attribute attribute : getCurrentAttributes()) { tableNames.add(attribute.getTableName()); } return tableNames; } // ----------------------------------------------------- // Config shortcuts // ----------------------------------------------------- public boolean hasComment() { return getEntityConfig().hasComment(); } public String getComment() { return getEntityConfig().getComment(); } public String getCommentAsJavadoc() { return getEntityConfig().getCommentAsJavadoc(); } public List<Attribute> printerAttributes() { List<Attribute> result = newArrayList(); // configuration has priority: for (Attribute a : attributes.getList()) { if (a.getColumnConfig().getSelectLabel() != null && a.getColumnConfig().getSelectLabel()) { result.add(a); } } // then business key... if (result.isEmpty() && useBusinessKey()) { for (Attribute a : getBusinessKey()) { if (!a.isPassword()) { if (a.isSimple()) { result.add(a); } } } } // attempt to use naming convention if (result.isEmpty() || result.size() < 2) { for (Attribute a : labelAttributes.getList()) { if (!a.isPassword()) { result.add(a); if (result.size() > 2) { break; } } } } // attempt get first 3 unique columns if (result.isEmpty()) { for (Attribute a : simpleAttributes.getList()) { if (a.isUnique() && !a.isPassword()) { result.add(a); if (result.size() > 2) { break; } } } } // attempt get first 3 non nullable string column not part of file (expect filename which interest us) if (result.isEmpty()) { for (Attribute a : simpleAttributes.getList()) { if (a.isString() && a.isNotNullable()) { if (!a.isInFileDefinition() || a.isFilename()) { result.add(a); if (result.size() > 2) { break; } } } } } // attempt get first 3 string column if (result.isEmpty()) { for (Attribute a : simpleAttributes.getList()) { if ((a.isString() || a.isFilename()) && !a.isPassword()) { result.add(a); if (result.size() > 2) { break; } } } } // last resort add first 3 attribute if (result.isEmpty()) { for (Attribute a : simpleAttributes.getList()) { if (!a.isPassword()) { result.add(a); if (result.size() > 2) { break; } } } } if (result.isEmpty() && hasSimplePk()) { result.add(getRoot().getPrimaryKey().getAttribute()); } return unmodifiableList(result); } public List<Attribute> stringPrinterAttributes() { List<Attribute> result = newArrayList(); for (Attribute attribute : printerAttributes()) { if (attribute.isString()) { result.add(attribute); } } return unmodifiableList(result); } public List<Attribute> indexedPrinterAttributes() { List<Attribute> result = newArrayList(); for (Attribute attribute : printerAttributes()) { if (attribute.isIndexed()) { result.add(attribute); } } return unmodifiableList(result); } public String getSpaceAndExtendsStatement() { if (isRoot() && getEntityConfig().hasExtendsClass()) { return " extends " + getEntityConfig().getExtendsClass().getFullType(); } return ""; } public String getCommaAndImplementedInterfaces() { StringBuilder sb = new StringBuilder(""); if (getEntityConfig().hasImplementsInterfaces()) { for (ImplementsInterface inter : getEntityConfig().getImplementsInterfaces()) { if (inter.hasFullType()) { sb.append(", ").append(inter.getFullType()); } } } if (getConfig().getCelerio().getConfiguration().has(Module.COPYABLE)) { sb.append(", Copyable<" + getModel().getType() + ">"); } return sb.toString(); } // ---------------------------------------- // Account/Role attributes // ---------------------------------------- public boolean isAccount() { return accountAttributes != null; } public boolean isRole() { return roleAttributes != null; } AuditLogConvention auditLogConvention = null; public boolean isAuditLog() { if (auditLogConvention == null) { auditLogConvention = new AuditLogConvention(this); } return auditLogConvention.isMatch(); } public AuditLogAttribute getAuditLogAttributes() { return auditLogConvention.getAuditLogAttribute(); } SavedSearchConvention savedSearchConvention = null; public boolean isSavedSearch() { if (isManyToManyJoinEntity()) { return false; } if (savedSearchConvention == null) { savedSearchConvention = new SavedSearchConvention(this); } return savedSearchConvention.isMatch(); } public SavedSearchAttributes getSavedSearchAttributes() { return savedSearchConvention.getSavedSearchAttributes(); } AuditEntityConvention auditEntityConvention = null; public boolean isEntityAudited() { if (auditEntityConvention == null) { auditEntityConvention = new AuditEntityConvention(this); } return auditEntityConvention.isAudited(); } public AuditEntityAttribute getAuditEntityAttributes() { if (auditEntityConvention == null) { auditEntityConvention = new AuditEntityConvention(this); } return auditEntityConvention.getAuditEntityAttribute(); } // ---------------------------------------- // Files // ---------------------------------------- private Boolean hasFileAttributes; public boolean hasFileAttributes() { if (hasFileAttributes == null) { hasFileAttributes = HAS_FILE_ATTRIBUTES.apply(this); } return hasFileAttributes; } // ---------------------------------------- // Identifiable // ---------------------------------------- /** * Tells whether we should generate identifiable methods. We do not need to generate them in the case where the identifiable property matches exactly the * entity's PK field. */ public boolean generateIdentifiableMethods() { Assert.isTrue(isRoot(), "generateIdentifiableMethods() can be invoked only on root entity. Please fix your template."); if (hasSimplePk() || hasCompositePk()) { String identifiableProperty = config.getCelerio().getConfiguration().getConventions() .getIdentifiableProperty(); // keep it with equalsIgnoreCase as people tends to use 'Id' return !getPrimaryKey().getVar().equalsIgnoreCase(identifiableProperty); } return true; } // ---------------------------------------- // Support for localized database schema (columns example: text_fr, text_en, text_de) // ---------------------------------------- List<AttributeBundle> attributeBundles; /** * we should also check on types. */ public List<AttributeBundle> getAttributeBundles() { if (attributeBundles != null) { return attributeBundles; } Map<String, AttributeBundle> bundlesMap = newHashMap(); for (Attribute attribute : getAttributes().getList()) { if (attribute.columnNameHasLanguageSuffix()) { String base = attribute.getColumnNameWithoutLanguage(); AttributeBundle bundle = bundlesMap.get(base); if (bundle == null) { bundle = new AttributeBundle(attribute); // add first attribute bundlesMap.put(base, bundle); } else { bundle.addAttribute(attribute); } } } // keep bundles with more than 1 attribute attributeBundles = newArrayList(); for (AttributeBundle bundle : bundlesMap.values()) { if (bundle.getAttributes().size() > 1) { attributeBundles.add(bundle); log.info("Found columns satisfying localization pattern: " + bundle.toString()); } } return attributeBundles; } // ---------------------------------------- // Misc // ---------------------------------------- public boolean useBusinessKey() { return businessKey.size() > 0; } /** * In case this entity is used as a many to one target. Which attribute should be used for sorting. */ public Attribute getXToOneSortAttribute() { // must be consistent with formatter... return printerAttributes.getFlatUp().getFirst(); } public boolean hasDateAttribute() { return any(currentAttributes, DATE); } public boolean hasUniqueDateAttribute() { return any(currentAttributes, and(DATE, IS_UNIQUE)); } public boolean hasUniqueBigIntegerAttribute() { return any(currentAttributes, and(BIG_INTEGER, IS_UNIQUE)); } public boolean hasUniqueAttribute() { return any(currentAttributes, IS_BINARY_SUFFIX); } public boolean overrideDeleteInManagerImpl() { if (!isManyToManyJoinEntity() && !isView()) { for (Relation r : relations.getList()) { // TODO: move into Relation if (r.hasInverse() && (r.getInverse().isOneToMany() || r.getInverse().isOneToOne())) { return true; } } } return false; } public boolean is(InheritanceType strategy) { Assert.notNull(strategy); if (getInheritance() == null) { return false; } return strategy == getInheritance().getStrategy(); } public boolean isTable() { return !isView() && !isVirtual(); } public List<Entity> getMandatoryToEntitiesUpToRoot() { List<Entity> result = newArrayList(); for (Relation r : getRelations().getFlatUp().getList()) { if (r.isMandatory()) { if (!result.contains(r.getToEntity())) { result.add(r.getToEntity()); } } } return result; } /** * @return true when this entity can be edited directly, false when it should be edited after navigating through it from another entity. */ public boolean isDrivesAllRelations() { for (Relation r : getRelations().getFlatUp().getList()) { if (!r.getFromEntity().equals(r.getToEntity())) { if (r.isManyToOne() && r.hasInverse()) { return false; } if (r.isOneToOne() && r.hasInverse() && !r.isInverse()) { return false; } } } return true; } // ---------------------------------------- // Hibernate Search // ---------------------------------------- /** * Whether this entity is indexed by hibernate search. When true, we can use full text search on front side. */ public boolean isIndexed() { return getEntityConfig().hasTrueIndexed() || getEntityConfig().atLeastOneColumnConfigIsIndexed(); } // ----------------------------------------------------- // Internationalization // ----------------------------------------------------- private Labels labels; public String getLabelName() { return getModel().getVar(); } public Labels getLabels() { if (labels == null) { labels = new Labels(entityConfig.getLabels()); labels.setFallBack(fallBack(entityConfig.getLabel(), toReadableLabel(entityConfig.getEntityName()))); } return labels; } // ----------------------------------------------------- // equals & hashCode // ----------------------------------------------------- @Override final public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof Entity)) { return false; } Entity other = (Entity) o; if (getName() != null && getName().length() > 0) { return getName().equals(other.getName()); } else { throw new IllegalStateException("equals is called whereas 'name' is not yet set, this is dangerous"); } } @Override final public int hashCode() { if (getName() != null && getName().length() > 0) { return getName().hashCode(); } else { throw new IllegalStateException("hashCode is called whereas 'name' is not yet set, this is dangerous"); } } // ----------------------------------------------------- // Builders to lower the attributes declarations // ----------------------------------------------------- private EntityUniques newEntityUniques() { return new EntityUniques(this, UNIQUES); } private EntityUniques newEntityUniques(Predicate<Unique> predicate) { return new EntityUniques(this, UNIQUES, predicate); } private EntityRelations newEntityRelations() { return new EntityRelations(this, RELATIONS); } private EntityRelations newEntityRelations(Predicate<Relation> predicate) { return new EntityRelations(this, RELATIONS, predicate); } private EntityAttributes newEntityAttributes() { return new EntityAttributes(this, ATTRIBUTES); } private EntityAttributes newEntityAttributes(Predicate<Attribute> predicate) { return new EntityAttributes(this, ATTRIBUTES, predicate); } private EntityAttributes newEntityAttributes(Predicate<Attribute> predicate, AttributeOrder attributeOrder) { return new EntityAttributes(this, ATTRIBUTES, predicate, attributeOrder); } private EntityAttributes newEntityAttributes(Predicate<Attribute> p1, Predicate<Attribute> p2) { return new EntityAttributes(this, ATTRIBUTES, Predicates.<Attribute>and(p1, p2)); // using static import breaks compilation } private EntityAttributes newEntityAttributes(Predicate<Attribute> p1, Predicate<Attribute> p2, AttributeOrder attributeOrder) { return new EntityAttributes(this, ATTRIBUTES, Predicates.<Attribute>and(p1, p2), attributeOrder); // using static import breaks compilation } @SuppressWarnings("unchecked") private EntityAttributes newEntityAttributes(Predicate<Attribute> p1, Predicate<Attribute> p2, Predicate<Attribute> p3) { return new EntityAttributes(this, ATTRIBUTES, Predicates.<Attribute>and(p1, p2, p3)); // using static import breaks compilation } // private EntityPackageImports newEntityPackageImports(ListGetter<PackageImport, Entity> listGetter) { // return new EntityPackageImports(this, listGetter); // } private Namer newClassNamer(ClassType type) { return new ClassNamer(this, type); } private EntityEntity newEntityEntity() { return newEntityEntity(RELATED_ENTITIES); } private EntityEntity newEntityEntity(ListGetter<Entity, Entity> listGetter) { return new EntityEntity(this, listGetter); } private EntityEntity newEntityEntity(Predicate<Entity> predicate) { return new EntityEntity(this, RELATED_ENTITIES, predicate); } // FIXME: rapid patch for demo public List<Entity> getAllChildrenRecursive() { List<Entity> result = newArrayList(); if (isRoot()) { allChildrenRecursive(this, result); } return result; } // rapid patch private void allChildrenRecursive(Entity e, List<Entity> result) { for (Entity child : e.getChildren()) { result.add(child); allChildrenRecursive(child, result); } } public CollectionType getCollectionType() { return getEntityConfig().getCollectionType(); } // ------------------------------------ // SPI / Custom Namer are put in a Map so we can access // from velocity templates as if we had getter. // ------------------------------------ private Map<String, Object> spis = newHashMap(); @Override public void clear() { spis.clear(); } @Override public boolean containsKey(Object arg0) { return spis.containsKey(arg0); } @Override public boolean containsValue(Object arg0) { return spis.containsValue(arg0); } @Override public Set<java.util.Map.Entry<String, Object>> entrySet() { return spis.entrySet(); } @Override public Object get(Object arg0) { Object o = spis.get(arg0); Preconditions.checkNotNull(o, "No SPI having its var=" + arg0 + " was found. Tip: in your template for predicate method, use always ref.isSomething() instead of xxx.something"); return o; } @Override public boolean isEmpty() { return spis.isEmpty(); } @Override public Set<String> keySet() { return spis.keySet(); } @Override public Object put(String arg0, Object arg1) { return spis.put(arg0, arg1); } @Override public void putAll(Map<? extends String, ? extends Object> arg0) { spis.putAll(arg0); } @Override public Object remove(Object arg0) { return spis.remove(arg0); } @Override public int size() { return spis.size(); } @Override public Collection<Object> values() { return spis.values(); } }