All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.ird.observe.services.service.referential.UnidirectionalSynchronizeEngine Maven / Gradle / Ivy

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 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 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