org.nuiton.topia.service.sql.metadata.TopiaMetadataEntity Maven / Gradle / Ivy
package org.nuiton.topia.service.sql.metadata;
/*
* #%L
* Toolkit :: Templates
* %%
* Copyright (C) 2017 - 2024 Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.base.MoreObjects;
import io.ultreia.java4all.lang.Objects2;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.topia.persistence.TopiaEntity;
import java.sql.Blob;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Created on 03/01/16.
*
* @author Tony Chemit - [email protected]
* @since 3.0.1
*/
public class TopiaMetadataEntity implements Comparable {
private static final Logger log = LogManager.getLogger(TopiaMetadataEntity.class);
/**
* Optional parent type.
*/
protected final String parent;
/**
* TopiaEntityEnum name.
*/
protected final String type;
/**
* Fully qualified name of entity.
*/
protected final String fullyQualifiedName;
/**
* Is abstract?
*/
protected final boolean isAbstract;
/**
* Is entry point?
*/
protected final boolean entryPoint;
/**
* Db schema name.
*/
protected final String dbSchemaName;
/**
* Db table name.
*/
protected final String dbTableName;
/**
* One to many associations (keys are property name, values are type).
*/
protected final Map oneToManyAssociations = new LinkedHashMap<>();
/**
* One to one compositions (keys are property name, values are type).
*/
protected final Map oneToOneCompositions = new LinkedHashMap<>();
/**
* Target types of one to many relations. (To get column, use getDbColumName from here).
*/
protected final Set oneToOneCompositionInverses = new TreeSet<>();
/**
* Target types of one to many relations. (To get column, use getDbColumName from here).
*/
protected final Set oneToManyAssociationInverses = new TreeSet<>();
/**
* Many to many associations (keys are property name, values are type).
*/
protected final Map reversedAssociations = new LinkedHashMap<>();
/**
* Many to many associations (keys are property name, values are type).
*/
protected final Map manyToManyAssociations = new LinkedHashMap<>();
/**
* Many to one associations (keys are property name, values are type).
*/
protected final Map manyToOneAssociations = new LinkedHashMap<>();
/**
* Many associations (keys are property name, values are type).
*/
protected final Map manyAssociations = new LinkedHashMap<>();
/**
* Properties (keys are property name, values are type).
*/
protected final Map properties = new LinkedHashMap<>();
/**
* Decimal properties scales (keys are property name, values are scales).
*/
protected final Map decimalPropertiesScales = new LinkedHashMap<>();
/**
* Enumeration properties using enumeration name.
*/
protected final Set enumerationPropertiesUsingName = new LinkedHashSet<>();
/**
* Blob properties.
*/
protected final Set blobProperties = new LinkedHashSet<>();
/**
* Extra columns.
*/
protected final Set extraColumnNames = new LinkedHashSet<>();
/**
* Le nom des colunnes correspondants aux propriétés de l'entité.
* Note: On ne conserve que les correspondances qui diffèrent du nom de la propriété.
*
* @see #getDbColumnName(String)
*/
protected final Map dbColumnsName = new LinkedHashMap<>();
/**
* Le nom des tables utilisées pour les associations nm.
*/
protected final Map dbManyToManyAssociationsTableName = new LinkedHashMap<>();
/**
* Le nom des tables utilisées pour les associations simples nm.
*/
protected final Map dbManyAssociationsTableName = new LinkedHashMap<>();
private final boolean standalone;
/**
* Get all property we do not want to navigate on.
*/
private final Set skipNavigation = new LinkedHashSet<>();
protected Set allDbColumnNames;
public static List toFqn(Collection entities) {
return entities.stream().map(TopiaMetadataEntity::getFullyQualifiedName).collect(Collectors.toList());
}
public static List sortByFqn(Collection entities) {
return sortByFqn(entities.stream());
}
public static List sortByFqn(Stream entities) {
return streamSortByFqn(entities).collect(Collectors.toList());
}
public static Stream streamSortByFqn(Stream entities) {
return entities.sorted(Comparator.comparing(TopiaMetadataEntity::getFullyQualifiedName));
}
public TopiaMetadataEntity(String parent, String type, String fullyQualifiedName, boolean isAbstract, boolean entryPoint, boolean standalone, String dbSchemaName, String dbTableName) {
this.parent = parent;
this.type = type;
this.fullyQualifiedName = fullyQualifiedName;
this.isAbstract = isAbstract;
this.entryPoint = entryPoint;
this.standalone = standalone;
this.dbSchemaName = dbSchemaName;
this.dbTableName = dbTableName;
}
public void putAll(TopiaMetadataEntity parent) {
putAll(getOneToManyAssociations(), parent.getOneToManyAssociations());
putAll(getOneToOneCompositions(), parent.getOneToOneCompositions());
addAll(getOneToOneCompositionInverses(), parent.getOneToOneCompositionInverses());
addAll(getOneToManyAssociationInverses(), parent.getOneToManyAssociationInverses());
putAll(getReversedAssociations(), parent.getReversedAssociations());
putAll(getManyToManyAssociations(), parent.getManyToManyAssociations());
putAll(getManyToOneAssociations(), parent.getManyToOneAssociations());
putAll(getManyAssociations(), parent.getManyAssociations());
putAll(getProperties(), parent.getProperties());
addAll(getExtraColumnNames(), parent.getExtraColumnNames());
putAll(getDbColumnsName(), parent.getDbColumnsName());
putAll(getDbColumnsName(), parent.getDbManyToManyAssociationsTableName());
putAll(getDecimalPropertiesScales(), parent.getDecimalPropertiesScales());
addAll(getSkipNavigation(), parent.getSkipNavigation());
}
private void addAll(Set current, Set parent) {
Set result = new LinkedHashSet<>(parent);
result.addAll(current);
current.clear();
current.addAll(result);
}
private void putAll(Map current, Map parent) {
Map result = new LinkedHashMap<>(parent);
result.putAll(current);
current.clear();
current.putAll(result);
}
public String getType() {
return type;
}
public String getFullyQualifiedName() {
return fullyQualifiedName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TopiaMetadataEntity that = (TopiaMetadataEntity) o;
return Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(type);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("type", type)
.add("dbName", dbSchemaName + "." + dbTableName)
.toString();
}
public String getParent() {
return parent;
}
public String getDbSchemaName() {
return dbSchemaName;
}
public String getSchemaAndTableName() {
return getDbSchemaName() + "." + getDbTableName();
}
public String getDbTableName() {
return dbTableName;
}
public boolean isAbstract() {
return isAbstract;
}
public boolean isEntryPoint() {
return entryPoint;
}
public boolean isStandalone() {
return standalone;
}
public Set getAllDbColumnNames() {
if (allDbColumnNames == null) {
allDbColumnNames = new LinkedHashSet<>();
allDbColumnNames.add(TopiaEntity.PROPERTY_TOPIA_ID);
allDbColumnNames.add(TopiaEntity.PROPERTY_TOPIA_CREATE_DATE);
allDbColumnNames.add(TopiaEntity.PROPERTY_TOPIA_VERSION);
allDbColumnNames.addAll(extraColumnNames);
allDbColumnNames.addAll(getProperties().keySet().stream()
.map(this::getDbColumnName)
.collect(Collectors.toCollection(LinkedHashSet::new)));
allDbColumnNames.addAll(getManyToOneAssociations().keySet().stream()
.map(this::getDbColumnName)
.collect(Collectors.toCollection(LinkedHashSet::new)));
allDbColumnNames.addAll(getReversedAssociations().keySet().stream()
.map(this::getDbColumnName)
.collect(Collectors.toCollection(LinkedHashSet::new)));
allDbColumnNames.addAll(getOneToManyAssociationInverses().stream()
.map(this::getDbColumnName)
.collect(Collectors.toCollection(LinkedHashSet::new)));
allDbColumnNames.addAll(getOneToOneCompositionInverses().stream()
.map(this::getDbColumnName)
.collect(Collectors.toCollection(LinkedHashSet::new)));
}
return allDbColumnNames;
}
public Map getReversedAssociations() {
return reversedAssociations;
}
public Map getManyToManyAssociations() {
return manyToManyAssociations;
}
public Map getOneToManyAssociations() {
return oneToManyAssociations;
}
public Map getOneToOneCompositions() {
return oneToOneCompositions;
}
public Set getOneToOneCompositionInverses() {
return oneToOneCompositionInverses;
}
public Map getManyToOneAssociations() {
return manyToOneAssociations;
}
public Map getManyAssociations() {
return manyAssociations;
}
public Set getOneToManyAssociationInverses() {
return oneToManyAssociationInverses;
}
public Map getProperties() {
return properties;
}
public Map getDecimalPropertiesScales() {
return decimalPropertiesScales;
}
public Set getEnumerationPropertiesUsingName() {
return enumerationPropertiesUsingName;
}
public Set getDbEnumerationPropertiesUsingName() {
Set result = new TreeSet<>();
for (String propertyName : getEnumerationPropertiesUsingName()) {
String dbColumnName = getDbColumnName(propertyName);
result.add(dbColumnName);
}
return result;
}
/**
* @return dictionary of db columns with their types (keys are column names, values are fully qualified types)
*/
public Map> getDbSimplePropertiesTypes() {
Map> result = new TreeMap<>();
for (Map.Entry entry : properties.entrySet()) {
String dbColumnName = getDbColumnName(entry.getKey());
String typeName = entry.getValue();
Class> type;
//FIXME Move this to java-lang project
if (typeName.equals("boolean")) {
type = boolean.class;
} else if (typeName.equals("int")) {
type = int.class;
} else {
type = Objects2.forName(typeName);
}
result.put(dbColumnName, type);
}
return result;
}
/**
* @return dictionary of decimal db columns with their precision (keys are column names and values are number of digits)
*/
public Map getDbDecimalPrecisions() {
Map result = new TreeMap<>();
for (Map.Entry entry : decimalPropertiesScales.entrySet()) {
String dbColumnName = getDbColumnName(entry.getKey());
result.put(dbColumnName, entry.getValue());
}
return result;
}
public Set getExtraColumnNames() {
return extraColumnNames;
}
public Set getSkipNavigation() {
return skipNavigation;
}
public boolean withBlob() {
return !blobProperties.isEmpty();
}
public Set getBlobProperties() {
return blobProperties;
}
public Map getDbColumnsName() {
return dbColumnsName;
}
public String getDbColumnName(String propertyName) {
String dbColumnName = dbColumnsName.get(propertyName);
if (dbColumnName == null) {
dbColumnName = propertyName;
}
return dbColumnName;
}
public Optional getOptionalRecursiveProperty() {
return getManyToOneAssociations().entrySet().stream().filter(f -> f.getValue().equals(getType())).map(Map.Entry::getKey).findFirst();
}
public Map getDbManyToManyAssociationsTableName() {
return dbManyToManyAssociationsTableName;
}
public Map getDbManyAssociationsTableName() {
return dbManyAssociationsTableName;
}
public String getBdManyToManyAssociationTableName(String propertyName) {
return dbManyToManyAssociationsTableName.get(propertyName);
}
public String getBdManyAssociationTableName(String propertyName) {
return dbManyAssociationsTableName.get(propertyName);
}
public void addOneToManyAssociation(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
oneToManyAssociations.put(name, associationClazz.getType());
addDbColumnName(name, dbColumnName);
}
public void addExtraColumn(String extraColumn) {
extraColumnNames.add(extraColumn);
}
public void addOneToManyAssociationInverse(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
oneToManyAssociationInverses.add(name);
addDbColumnName(name, dbColumnName);
}
public void addOneToOneAssociationInverse(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
oneToOneCompositionInverses.add(name);
addDbColumnName(name, dbColumnName);
}
public void addOneToOneAssociation(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
oneToOneCompositions.put(name, associationClazz.getType());
// addDbColumnName(name, dbColumnName);
}
public void addReversedAssociation(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
reversedAssociations.put(name, associationClazz.getType());
addDbColumnName(name, dbColumnName);
}
public void addManyToManyAssociation(TopiaMetadataEntity associationClazz, String name, String dbColumnName, String dbManyToManyAssociationTableName, String reverseDbColumnName) {
log.debug(getType() + "/" + name + "(" + dbManyToManyAssociationTableName + ") →" + associationClazz.getType());
manyToManyAssociations.put(name, associationClazz.getType());
addDbColumnName(name, dbColumnName);
if (reverseDbColumnName != null) {
addDbColumnName(dbManyToManyAssociationTableName, reverseDbColumnName);
}
dbManyToManyAssociationsTableName.put(name, dbManyToManyAssociationTableName);
}
public void addManyAssociation(String name, String dbColumnName, String dbManyToManyAssociationTableName, String reverseDbColumnName, String type) {
log.debug(getType() + "/" + name + "(" + dbManyToManyAssociationTableName + ") →" + type);
manyAssociations.put(name, type);
addDbColumnName(name, dbColumnName);
if (reverseDbColumnName != null) {
addDbColumnName(dbManyToManyAssociationTableName, reverseDbColumnName);
}
dbManyAssociationsTableName.put(name, dbManyToManyAssociationTableName);
}
public void addManyToOneAssociation(TopiaMetadataEntity associationClazz, String name, String dbColumnName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + associationClazz.getType());
manyToOneAssociations.put(name, associationClazz.getType());
addDbColumnName(name, dbColumnName);
}
public void addProperty(String name, String type, String dbColumnName, Integer precision, Boolean useEnumerationName) {
log.debug(getType() + "/" + name + "(" + dbColumnName + ") →" + type);
properties.put(name, type);
if (Blob.class.getName().equals(type)) {
blobProperties.add(name);
}
if (precision != null) {
decimalPropertiesScales.put(name, precision);
}
if (useEnumerationName != null && useEnumerationName) {
enumerationPropertiesUsingName.add(name);
}
addDbColumnName(name, dbColumnName);
}
public void accept(TopiaMetadataModelVisitor visitor, TopiaMetadataModel metadataModel) {
visitor.visitEntityStart(metadataModel, this);
for (Map.Entry entry : reversedAssociations.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitReversedAssociation(metadataModel, this, propertyName, metadataModel.getEntity(propertyType));
}
for (Map.Entry entry : oneToManyAssociations.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitOneToManyAssociation(metadataModel, this, propertyName, metadataModel.getEntity(propertyType));
}
for (Map.Entry entry : oneToOneCompositions.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitOneToOneAssociation(metadataModel, this, propertyName, metadataModel.getEntity(propertyType));
}
for (String propertyType : oneToManyAssociationInverses) {
visitor.visitOneToManyAssociationInverse(metadataModel, this, propertyType, metadataModel.getEntity(propertyType));
}
//FIXME
// for (String propertyType : oneToOneCompositionInverses) {
// visitor.visitOneToManyAssociationInverse(metadataModel, this, propertyType, metadataModel.getEntity(propertyType));
// }
for (Map.Entry entry : manyToManyAssociations.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitManyToManyAssociation(metadataModel, this, propertyName, metadataModel.getEntity(propertyType));
}
for (Map.Entry entry : manyAssociations.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitManyAssociation(metadataModel, this, propertyName, propertyType);
}
for (Map.Entry entry : manyToOneAssociations.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitManyToOneAssociation(metadataModel, this, propertyName, metadataModel.getEntity(propertyType));
}
for (Map.Entry entry : properties.entrySet()) {
String propertyName = entry.getKey();
String propertyType = entry.getValue();
visitor.visitProperty(metadataModel, this, propertyName, propertyType);
}
visitor.visitEntityEnd(metadataModel, this);
}
private void addDbColumnName(String name, String dbColumnName) {
if (!name.equals(dbColumnName)) {
dbColumnsName.put(name, dbColumnName);
}
}
public void addSkipNavigation(String name) {
skipNavigation.add(name);
}
public boolean isSkipNavigation(String name) {
return skipNavigation.contains(name);
}
@Override
public int compareTo(TopiaMetadataEntity o) {
return getFullyQualifiedName().compareTo(o.getFullyQualifiedName());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy