
org.nuiton.topia.templates.sql.order.ReplicationOrderBuilder Maven / Gradle / Ivy
package org.nuiton.topia.templates.sql.order;
/*-
* #%L
* ToPIA Extension :: Templates
* %%
* Copyright (C) 2018 - 2022 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.collect.ArrayListMultimap;
import org.apache.commons.lang3.mutable.MutableInt;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataAssociation;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataComposition;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataEntity;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataEntityPath;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataModel;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataModelPaths;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataOneToOneComposition;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataReverseAssociation;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* To compute for a set of entities, the replication order.
*
* Created on 24/09/2020.
*
* @author Tony Chemit - [email protected]
* @since 1.27
*/
public abstract class ReplicationOrderBuilder {
/**
* Metadata model used to build order.
*/
private final TopiaMetadataModel metadataModel;
/**
* All entities used in this sub model.
*/
private final Set entities;
protected ReplicationOrderBuilder(TopiaMetadataModel metadataModel, Set entities) {
this.metadataModel = Objects.requireNonNull(metadataModel);
this.entities = Objects.requireNonNull(entities);
}
public abstract List build();
protected ArrayListMultimap computeDependencies(Collection entities) {
ArrayListMultimap dependenciesMapping = ArrayListMultimap.create();
for (TopiaMetadataEntity entity : TopiaMetadataEntity.sortByFqn(entities)) {
List dependencies = getDependencies(entity);
if (!dependencies.isEmpty()) {
dependenciesMapping.putAll(entity, dependencies);
}
}
return dependenciesMapping;
}
public Set getEntities() {
return entities;
}
protected List getDependencies(TopiaMetadataEntity entity) {
Set result = new LinkedHashSet<>();
for (TopiaMetadataAssociation link : metadataModel.getAssociations(entity)) {
result.add(link.getTarget());
}
for (TopiaMetadataComposition link : metadataModel.getCompositions(entity)) {
result.add(link.getTarget());
}
for (TopiaMetadataAssociation link : metadataModel.getReverseOneToManyAssociations(entity)) {
result.add(link.getOwner());
}
for (TopiaMetadataOneToOneComposition link : metadataModel.getReverseOneToOneAssociations(entity)) {
result.add(link.getOwner());
}
for (TopiaMetadataReverseAssociation link : metadataModel.getReverseAssociations(entity)) {
result.add(link.getTarget());
}
// if entity has a recursive link, do not add it as dependency
result.remove(entity);
return TopiaMetadataEntity.sortByFqn(result);
}
public ArrayListMultimap computeReducedPathsMapping(TopiaMetadataModelPaths allPathsModel, Collection entities) {
// first pass to fill all paths
List allPaths = new LinkedList<>();
for (TopiaMetadataEntity entity : entities) {
List paths = allPathsModel.getEntityPath(entity);
allPaths.addAll(paths);
}
// get links by higher size
allPaths.sort(Comparator.comparing(TopiaMetadataEntityPath::getLinksSize).reversed());
// second path to keep only longest paths (sub paths are ignored)
Set allPathsToEvict = new LinkedHashSet<>();
for (TopiaMetadataEntityPath path : allPaths) {
if (allPathsToEvict.contains(path)) {
continue;
}
TopiaMetadataEntityPath parent = path.parent();
while (parent != null) {
allPathsToEvict.add(parent);
parent = parent.parent();
}
}
ArrayListMultimap pathsMapping = ArrayListMultimap.create();
allPaths.removeAll(allPathsToEvict);
for (TopiaMetadataEntityPath path : allPaths) {
pathsMapping.put(path.getEnd(), path);
}
//TODO Using this add more paths
//TODO Result is not the same at the end
//TODO Maybe this result could be more efficient, need more tests
// for (TopiaMetadataEntity entity : entities) {
// if (!pathsMapping.containsKey(entity)) {
// // need to get it back
// Collection paths = getEntityPath(entity);
// pathsMapping.putAll(entity, paths);
// }
// }
return pathsMapping;
}
public ArrayListMultimap computePathsCount(ArrayListMultimap pathsMapping) {
ArrayListMultimap pathsCount = ArrayListMultimap.create();
for (Map.Entry> entry : pathsMapping.asMap().entrySet()) {
Collection paths = entry.getValue();
TopiaMetadataEntity entity = entry.getKey();
if (paths.isEmpty()) {
pathsCount.put(new MutableInt(0), entity);
} else {
for (TopiaMetadataEntityPath path : paths) {
int size = path.getLinks().size();
pathsCount.put(new MutableInt(size), entity);
}
}
}
return pathsCount;
}
}