fr.ird.observe.services.service.referential.UnidirectionalSynchronizeEngine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of toolkit-service Show documentation
Show all versions of toolkit-service Show documentation
ObServe Toolkit Service module
The newest version!
package fr.ird.observe.services.service.referential;
/*-
* #%L
* ObServe Toolkit :: Service
* %%
* Copyright (C) 2017 - 2021 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 fr.ird.observe.dto.ProgressionModel;
import fr.ird.observe.dto.ToolkitIdLabel;
import fr.ird.observe.dto.ToolkitIdTechnicalLabel;
import fr.ird.observe.dto.referential.ReferentialDto;
import fr.ird.observe.spi.referential.differential.Differential;
import fr.ird.observe.spi.referential.differential.DifferentialList;
import fr.ird.observe.spi.referential.differential.DifferentialModel;
import fr.ird.observe.spi.referential.differential.DifferentialModelBuilder;
import fr.ird.observe.spi.referential.differential.DifferentialType;
import fr.ird.observe.spi.referential.synchro.BothSideSqlResult;
import fr.ird.observe.spi.referential.synchro.BothSidesSqlRequest;
import fr.ird.observe.spi.referential.synchro.SynchronizeTask;
import fr.ird.observe.spi.referential.synchro.SynchronizeTaskType;
import fr.ird.observe.spi.referential.synchro.UnidirectionalCallbackRequests;
import fr.ird.observe.spi.referential.synchro.UnidirectionalCallbackResult;
import fr.ird.observe.spi.referential.synchro.UnidirectionalCallbackResults;
import fr.ird.observe.spi.referential.synchro.UnidirectionalResult;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.topia.persistence.script.TopiaSqlScript;
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Created on 28/06/16.
*
* @author Tony Chemit - [email protected]
* @since 5.0
*/
public class UnidirectionalSynchronizeEngine {
private static final Logger log = LogManager.getLogger(UnidirectionalSynchronizeEngine.class);
private final DifferentialModelBuilder diffsEngine;
private final SynchronizeEngine synchronizeEngine;
public UnidirectionalSynchronizeEngine(DifferentialModelBuilder diffsEngine, SynchronizeEngine synchronizeEngine) {
this.diffsEngine = Objects.requireNonNull(diffsEngine);
this.synchronizeEngine = Objects.requireNonNull(synchronizeEngine);
}
public UnidirectionalSynchronizeContext prepareContext(ProgressionModel progressionModel) {
if (progressionModel == null) {
progressionModel = new ProgressionModel();
progressionModel.addPropertyChangeListener(ProgressionModel.PROPERTY_MESSAGE, evt -> log.info(evt.getNewValue()));
}
DifferentialModel synchronizeDiffs = diffsEngine.build(progressionModel);
DifferentialList leftDiff = synchronizeDiffs.getLeft();
DifferentialList rightDiff = synchronizeDiffs.getRight();
Map, DifferentialList> leftDiffStates = leftDiff.getStatesByType();
Map, DifferentialList> rightDiffStates = rightDiff.getStatesByType();
Set> types = new LinkedHashSet<>(leftDiffStates.keySet());
types.addAll(rightDiffStates.keySet());
BothSidesSqlRequest.Builder sqlRequestBuilder = BothSidesSqlRequest.builder(leftDiff.getNewIds(), rightDiff.getNewIds());
Set> replicationOrder = diffsEngine.metaModel().replicationOrder();
Set> usedTypes = new LinkedHashSet<>();
UnidirectionalCallbackRequests callbackRequests = new UnidirectionalCallbackRequests();
// Première étape pour construire les builder de requète et calculer au passage les ids à faire remplacer par l'utilisateur
for (Class extends ReferentialDto> dtoType : replicationOrder) {
if (types.contains(dtoType)) {
boolean used = computeReferentialSynchronizeRequestBuilder(sqlRequestBuilder,
dtoType,
leftDiffStates,
rightDiffStates,
callbackRequests);
if (used) {
usedTypes.add(dtoType);
}
}
}
return new UnidirectionalSynchronizeContext(usedTypes, sqlRequestBuilder, callbackRequests);
}
public UnidirectionalResult prepareResult(UnidirectionalSynchronizeContext context, UnidirectionalCallbackResults callbackResults) {
UnidirectionalResult result = new UnidirectionalResult();
// Second étape pour terminer la construction des builders de requètes et générer le code sql
boolean needCallback = callbackResults != null;
BothSidesSqlRequest.Builder requestBuilders = context.getSqlRequestsBuilder();
for (Class extends ReferentialDto> referentialName : context.getUsedTypes()) {
if (needCallback && callbackResults.containsReferentialName(referentialName)) {
// l'utilisateur a agit sur ce référentiel, c'est une suppression avec remplacement
UnidirectionalCallbackResult> callbackResult = callbackResults.getCallbackResult(referentialName);
Map ids = callbackResult.getIds();
for (Map.Entry entry : ids.entrySet()) {
String idToReplace = entry.getKey();
requestBuilders.addTask(true, SynchronizeTaskType.DELETE, SynchronizeTask.createWithReplace(referentialName, idToReplace, null, entry.getValue()));
}
}
}
BothSidesSqlRequest referentialSynchronizeRequest = requestBuilders.build();
result.flushRequest(referentialSynchronizeRequest);
BothSideSqlResult generatedSqlRequests = synchronizeEngine.produceSql(referentialSynchronizeRequest);
Path scriptPath = synchronizeEngine.getTemporaryPath().resolve(String.format("UnidirectionalSynchronizeEngine-%d.sql", System.nanoTime()));
Optional topiaSqlScript = generatedSqlRequests.toLeftSqlScript(scriptPath);
topiaSqlScript.ifPresent(s -> {
log.info(String.format("Generate script at: %s", scriptPath));
context.setSqlScript(s);
context.setSqlScriptPath(scriptPath);
});
return result;
}
private boolean computeReferentialSynchronizeRequestBuilder(
BothSidesSqlRequest.Builder sqlRequestBuilder,
Class dtoType,
Map, DifferentialList> leftDiffStates,
Map, DifferentialList> rightDiffStates,
UnidirectionalCallbackRequests callbackRequests) {
boolean used = false;
List leftAddDifferentials = new LinkedList<>();
DifferentialList leftDifferentials = leftDiffStates.get(dtoType);
if (leftDifferentials != null) {
used = true;
for (Differential differential : leftDifferentials.getStates()) {
DifferentialType differentialType = differential.getDifferentialType();
switch (differentialType) {
case ADDED:
// on conserve ces objets car il faudra les remplacer dans la base locale
leftAddDifferentials.add(differential);
break;
case MODIFIED:
case DISABLED:
// On revient en arrière sur les référentiels de la base centrale
sqlRequestBuilder.addTask(true, SynchronizeTaskType.REVERT, createRevertTask(dtoType, differential));
break;
}
}
}
DifferentialList rightDifferentials = rightDiffStates.get(dtoType);
if (rightDifferentials != null) {
used = true;
for (Differential differential : rightDifferentials.getStates()) {
DifferentialType differentialType = differential.getDifferentialType();
switch (differentialType) {
case ADDED:
// Tous les référentiels ajoutés sur la base centrale doivent être copié en local
sqlRequestBuilder.addTask(false, SynchronizeTaskType.ADD, createTask(dtoType, differential));
break;
case MODIFIED:
case DISABLED:
// Tous les référentiels mises à jour dans la base centrale doivent être copié en local
sqlRequestBuilder.addTask(false, SynchronizeTaskType.UPDATE, createTask(dtoType, differential));
break;
}
}
}
// Tous les référentiels non présents dans la base centrale doivent être supprimés en local
if (!leftAddDifferentials.isEmpty()) {
Set idsToRemove = leftAddDifferentials.stream().map(Differential::getId).collect(Collectors.toCollection(LinkedHashSet::new));
Set blockingIdsToRemove = null;
if (!idsToRemove.isEmpty()) {
Set blockingIdsToRemoveFromLocal = synchronizeEngine.filterIdsUsedInLocalSource(dtoType, idsToRemove);
blockingIdsToRemove = idsToRemove
.stream()
.filter(blockingIdsToRemoveFromLocal::contains)
.collect(Collectors.toSet());
idsToRemove.removeAll(blockingIdsToRemove);
idsToRemove.forEach(id -> sqlRequestBuilder.addTask(true, SynchronizeTaskType.DELETE, SynchronizeTask.create(dtoType, id, null)));
}
boolean needCallback = blockingIdsToRemove != null && !blockingIdsToRemove.isEmpty();
if (needCallback) {
Set availableReferenceSet = diffsEngine.getRightEnabledReferentialLabelSet(dtoType);
Set blockingReferentialSetToRemove = synchronizeEngine.getLocalSourceReferentialToDelete(dtoType, blockingIdsToRemove);
callbackRequests.addCallbackRequest(dtoType, blockingReferentialSetToRemove, availableReferenceSet);
}
}
return used;
}
private SynchronizeTask createTask(Class dtoType, Differential differential) {
return SynchronizeTask.create(dtoType, differential.getId(), differential.getThisSideDto().getLastUpdateDate());
}
private SynchronizeTask createRevertTask(Class dtoType, Differential differential) {
ToolkitIdTechnicalLabel otherSideDto = differential.getOptionalOtherSideDto().orElseThrow();
return SynchronizeTask.create(dtoType, differential.getId(), otherSideDto.getLastUpdateDate());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy