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

org.nuiton.topia.replication.TopiaReplicationModelBuilder Maven / Gradle / Ivy

package org.nuiton.topia.replication;

/*
 * #%L
 * ToPIA :: Service Replication
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2004 - 2014 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.persistence.TopiaApplicationContext;
import org.nuiton.topia.persistence.TopiaException;
import org.nuiton.topia.persistence.TopiaPersistenceContext;
import org.nuiton.topia.persistence.TopiaEntity;
import org.nuiton.topia.persistence.TopiaEntityEnum;
import org.nuiton.topia.persistence.util.TopiaEntityHelper;
import org.nuiton.topia.replication.model.ReplicationModel;
import org.nuiton.topia.replication.model.ReplicationNode;
import org.nuiton.topia.replication.model.ReplicationOperationPhase;

import java.util.Arrays;
import java.util.Set;

/**
 * Builder of {@link ReplicationModel}.
 *
 * @author Tony Chemit - [email protected]
 * @since 2.4.3
 */
public class TopiaReplicationModelBuilder {

    /** Logger */
    private static final Log log =
            LogFactory.getLog(TopiaReplicationModelBuilder.class);

    /** Provider of {@link TopiaReplicationOperation}. */
    protected TopiaReplicationOperationProvider operationProvider;

    public TopiaReplicationOperationProvider getOperationProvider() {
        if (operationProvider == null) {
            operationProvider = new TopiaReplicationOperationProvider();
        }
        return operationProvider;
    }

    /**
     * Prepare le modele de replication pour les entites données dans
     * {@code topiaIds} et de leur couverture.
     *
     * Le paramètre {@code computeOrder} détermine si on doit calculer l'ordre
     * de replication des données (valeur à {@code true}), sinon (valeur
     * à {@code false}) on utilise l'ordre induit par le paramètre
     * {@code contracts}.
     *
     * @param context      le context de la base source (peut être utilisé
     *                     pour calculer l'ordre)
     * @param contracts    les contrats des types a repliquer
     * @param computeOrder drapeau positionné à {@code true} si on doit calculer
     *                     l'ordre de réplication, {@code false} si on utilise
     *                     l'ordre induit par le paramètre {@code contracts}.
     * @param topiaIds     les ids des entités à répliquer
     * @return le modele pour la replication
     * @throws TopiaException pour toute erreur rencontree
     */
    public ReplicationModel prepare(TopiaApplicationContext context,
                                    TopiaEntityEnum[] contracts,
                                    boolean computeOrder,
                                    String... topiaIds) throws TopiaException {
        ReplicationModel model =
                createModel(context, contracts, computeOrder, topiaIds);
        initModel(model, computeOrder);
        return model;
    }

    /**
     * Prepare le modele de replication pour toutes les entites des types
     * donnes.
     *
     * La méthode calcule l'ordre de replication des données.
     *
     * Actuellement, on n'est pas capable de calculer l'ordre si le graphe des
     * entités contient des cycles.
     *
     * TODO : faire en sorte de pouvoir gérer les cycles.
     *
     * @param contracts les contrats des types a repliquer
     * @return le modele pour la replication
     * @throws TopiaException pour toute erreur rencontree
     */
    public ReplicationModel prepareForAll(TopiaEntityEnum[] contracts) throws TopiaException {
        ReplicationModel model = createModelForAll(contracts);
        initModel(model, true);
        return model;
    }

    public void createOperation(ReplicationModel model,
                                TopiaEntityEnum type,
                                ReplicationOperationPhase phase,
                                Class operationClass,
                                Object... parameters) {

        TopiaEntityHelper.checkNotNull("createOperation", "model", model);
        TopiaEntityHelper.checkNotNull("createOperation", "type", type);
        TopiaEntityHelper.checkNotNull("createOperation", "phase", phase);
        TopiaEntityHelper.checkNotNull("createOperation", "operationClass", operationClass);

        TopiaReplicationOperation operation =
                getOperationProvider().getOperation(operationClass);

        if (operation == null) {
            throw new IllegalArgumentException(
                    String.format("The operation %1$s is unknown, known operations are: %2$s",
                      operationClass.getSimpleName(),
                      Arrays.toString(getOperationProvider().getOperations()))
            );
        }

        ReplicationNode node = model.getNode(type);
        if (node == null) {
            throw new IllegalArgumentException(
                    String.format("The target node (of type %1$s) for operation %2$s is unknown, known nodes are: %3$s",
                      type,
                      operationClass.getSimpleName(),
                      model.getNodes())
            );
        }
        operation.register(model, node, phase, parameters);
    }

    /**
     * Ajouter une nouvelle operation pre-replication, sur un type de donnee.
     *
     * @param model          le modele de replication
     * @param type           le type du noeud de replication
     * @param operationClass l'implantation de l'operation
     * @param parameters     les parametres supplementaires pour l'operation
     */
    public void addBeforeOperation(ReplicationModel model,
                                   TopiaEntityEnum type,
                                   Class operationClass,
                                   Object... parameters) {
        createOperation(
                model,
                type,
                ReplicationOperationPhase.before,
                operationClass,
                parameters
        );
    }

    /**
     * Ajouter une nouvelle operation post-replication, sur un type de donnee.
     *
     * @param model          le modele de replication
     * @param type           le type du noeud de replication
     * @param operationClass l'implantation de l'operation
     * @param parameters     les parametres supplementaires pour l'operation
     */
    public void addAfterOperation(ReplicationModel model,
                                  TopiaEntityEnum type,
                                  Class operationClass,
                                  Object... parameters) {
        createOperation(
                model,
                type,
                ReplicationOperationPhase.after,
                operationClass,
                parameters
        );
    }

    /**
     * Instantie un nouveau modèle de réplication pour les entités données par
     * leur ids.
     *
     * L'ordre de réplication dépend du paramètre {@code computeOrder}. Si
     * celui-ci vaut {@code true}, on calcule l'ordre de réplication, sinon on
     * utilise l'ordre induit par les {@code contracts}.
     *
     * @param context      le context Topia pour récupérer certainnes
     *                     informations de la base source si nécessaire.
     * @param contracts    les types d'entités
     * @param computeOrder drapeau pour calculer l'ordre de réplication
     *                     (valeur à {@code true}), sinon on utilise l'ordre
     *                     induit par les {@code contracts}.
     * @param topiaIds     les ids à dupliquer
     * @return le modèle crée mais non initialisé.
     * @throws TopiaException pour toute erreur lors de la création du modèle
     */
    public ReplicationModel createModel(TopiaApplicationContext context,
                                        TopiaEntityEnum[] contracts,
                                        boolean computeOrder,
                                        String... topiaIds)
            throws TopiaException {

        ReplicationModel model;

        if (computeOrder) {
            // determines types to use
            Set> detectTypes =
                    detectTypes(context, contracts, topiaIds);
            model = new ReplicationModel(contracts, detectTypes, topiaIds);
        } else {
            model = new ReplicationModel(contracts, false, topiaIds);

        }
        return model;
    }

    /**
     * Instantie un nouveau modèle de réplication pour toutes les entitées.
     *
     * Ici, l'ordre est toujours calculé.
     *
     * @param contracts les types d'entités
     * @return le modèle crée mais non initialisé.
     * @throws TopiaException pour toute erreur lors de la création du modèle
     */
    public ReplicationModel createModelForAll(TopiaEntityEnum[] contracts)
            throws TopiaException {
        ReplicationModel model = new ReplicationModel(contracts, true);
        return model;
    }

    public ReplicationModel initModel(ReplicationModel model,
                                      boolean computeOrder) throws TopiaException {
        TopiaEntityHelper.checkNotNull("initModel", "model", model);

        model.detectAssociations();
        model.detectDirectDependencies();
        if (computeOrder) {
            model.detectShell();
            model.detectDependencies();
        }
        model.detectObjectsToDettach();
        model.detectOperations();
        return model;
    }

    protected Set> detectTypes(TopiaApplicationContext context,
                                                            TopiaEntityEnum[] contracts,
                                                            String... ids) throws TopiaException {

        TopiaPersistenceContext ctxt = context.newPersistenceContext();
        try {
            TopiaEntity[] entities = TopiaEntityHelper.getEntities(ctxt, ids);

            // on detecte tous les types connus pour les entites données
            Set> types =
                    TopiaEntityHelper.detectTypes(contracts, entities);

            if (log.isDebugEnabled()) {
                log.debug("for type : " + entities.getClass());
                for (Class k : types) {
                    log.debug(k);
                }
            }
            return types;
        } finally {
            ctxt.close();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy