Author: tchemit Date: 2010-08-15 13:58:21 +0200 (Sun, 15 Aug 2010) New Revision: 2101 Url: http://nuiton.org/repositories/revision/topia/2101 Log: - sanitize replication api - decouple replication service and replication model builder Added: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilder.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilderImpl.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProvider.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProviderImpl.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationServiceImpl.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationLink.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractTopiaReplicationServiceTest.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplAllTest.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplTest.java Removed: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/ReplicationEngine.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/Link.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractReplicationEngineTest.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineAllTest.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineTest.java Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationImplementor.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationService.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationModel.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachAssociation.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachLink.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/DettachAssociation.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/Duplicate.java trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/LoadLink.java trunk/topia-service-replication/src/main/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationOperationTest.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/FakeOperation.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UncreatableOperation.java trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UnregistredOperation.java trunk/topia-service-replication/src/test/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation Deleted: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/ReplicationEngine.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/ReplicationEngine.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/ReplicationEngine.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,688 +0,0 @@ -/* - * #%L - * ToPIA :: Service Replication - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 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 - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.topia.replication; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.framework.TopiaContextImplementor; -import org.nuiton.topia.persistence.TopiaEntity; -import org.nuiton.topia.persistence.TopiaEntityEnum; -import org.nuiton.topia.persistence.util.TopiaEntityHelper; -import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; -import org.nuiton.topia.replication.model.ReplicationModel; -import org.nuiton.topia.replication.model.ReplicationNode; -import org.nuiton.topia.replication.model.ReplicationOperationDef; -import org.nuiton.topia.replication.model.ReplicationOperationPhase; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.ServiceLoader; -import java.util.Set; - -import static org.nuiton.i18n.I18n._; - -/** - * Implantation du service de replication. - * - * @author tchemit <chemit@codelutin.com> - * @since 2.2.0 - */ -public class ReplicationEngine implements TopiaReplicationImplementor { - - /** Logger */ - private static final Log log = LogFactory.getLog(ReplicationEngine.class); - - /** le contexte sur la base source de la replication */ - protected TopiaContextImplementor context; - - /** - * la liste des operations disponibles (chargee automatiquement via un - * ServiceLoader sur le contract {@link TopiaReplicationOperation}) - * - * @see #preInit(TopiaContextImplementor) - */ - protected TopiaReplicationOperation[] operations; - - //-------------------------------------------------------------------------- - //-- TopiaService implementation ------------------------------------------- - //-------------------------------------------------------------------------- - - @Override - public String getServiceName() { - return SERVICE_NAME; - } - - @Override - public Class<?>[] getPersistenceClasses() { - // pas de classes persistentes pour ce service - return null; - } - - @Override - public boolean preInit(TopiaContextImplementor context) { - if (operations == null) { - // chargement des operations disponibles une seule fois - - ServiceLoader<TopiaReplicationOperation> loader = - ServiceLoader.load(TopiaReplicationOperation.class); - - List<TopiaReplicationOperation> operations = - new ArrayList<TopiaReplicationOperation>(); - - for (TopiaReplicationOperation op : loader) { - if (log.isDebugEnabled()) { - log.debug("detected operation " + op); - } - operations.add(op); - } - this.operations = operations.toArray( - new TopiaReplicationOperation[operations.size()]); - } - return true; - } - - @Override - public boolean postInit(TopiaContextImplementor context) { - this.context = context; - //TODO avoir un objet pour lire les contrainte de resolution de cycle - //TODO sur les dependances (par exemple, une dependance marquee comme - // non nulle : ne peut jamais etre dettache, alors que dans le cas - // contraire on peut dettacher la dependance - // Cela permet de traiter plus de cas... - - //Properties prop = context.getConfig(); - return true; - } - - //-------------------------------------------------------------------------- - //-- TopiaReplicationService implementation -------------------------------- - //-------------------------------------------------------------------------- - - @Override - public ReplicationModel prepare(TopiaEntityEnum[] contracts, - String... entities) throws TopiaException { - ReplicationModel model = createModel(contracts, entities); - - initModel(model, true); - - return model; - } - - @Override - public ReplicationModel prepareForAll(TopiaEntityEnum[] contracts) throws TopiaException { - ReplicationModel model = createModelForAll(contracts); - - initModel(model, true); - - return model; - } - - @Override - public ReplicationModel prepareWithComputedOrder(TopiaEntityEnum[] contracts, - String... topiaIds) throws TopiaException { - ReplicationModel model = createModelWithComputedOrder(contracts, topiaIds); - - initModel(model, false); - - return model; - } - - @Override - public void addBeforeOperation(ReplicationModel model, - TopiaEntityEnum type, - Class<? extends TopiaReplicationOperation> operationClass, - Object... parameters) { - createOperation(model, - type, - ReplicationOperationPhase.before, - operationClass, - parameters - ); - } - - @Override - public void addAfterOperation(ReplicationModel model, - TopiaEntityEnum type, - Class<? extends TopiaReplicationOperation> operationClass, - Object... parameters) { - createOperation(model, - type, - ReplicationOperationPhase.after, - operationClass, - parameters - ); - } - - @Override - public void doReplicate(ReplicationModel model, - TopiaContext dstCtxt) throws Exception { - - checkNotNull("doReplicate", "model", model); - checkNotNull("doReplicate", "dstCtxt", dstCtxt); - - TopiaContextImplementor srcCtxt = null; - - TopiaEntityIdsMap data = null; - - // keep the list of treated nodes (to roolback them if something - // is wrong). - List<ReplicationNode> treated = new ArrayList<ReplicationNode>(); - try { - - srcCtxt = (TopiaContextImplementor) context.beginTransaction(); - - data = getIds(model, srcCtxt); - - srcCtxt.closeContext(); - - model.adjustOperations(data); - - //FIXME tchemit 2077-07-26, should use next line when - // http://nuiton.org/issues/show/779 is closed - boolean needTransaction = true; -// boolean needTransaction = ((TopiaContextImplementor) dstCtxt).getRootContext().equals(dstCtxt); - - TopiaContext tx; - - for (ReplicationNode node : model.getOrder()) { - - srcCtxt = (TopiaContextImplementor) context.beginTransaction(); - - if (needTransaction) { - tx = dstCtxt.beginTransaction(); - } else { - tx = dstCtxt; - } - try { - doReplicateNode(node, srcCtxt, tx, data, treated); - } catch (Exception e) { - - // un erreur est survenu sur le noeud de réplication - // on rollback la transaction de ce noeud - try { - tx.rollbackTransaction(); - } finally { - - // on revert les noeuds deja commite - doRollback(model, data, treated, dstCtxt); - } - - throw e; - } finally { - srcCtxt.closeContext(); - if (needTransaction) { - // on doit fermer la transaction car on l'a ouverte dans - // cette méthode, sinon c'est de la responsabilite du - // code appellant - tx.closeContext(); - } - } - } -// } catch (Exception e) { -// dstCtxt.rollbackTransaction(); -// throw e; - } finally { - if (data != null) { - data.clear(); - } - if (treated != null) { - treated.clear(); - } - // on ne doit jamais commiter sur la base source - if (srcCtxt != null && !srcCtxt.isClosed()) { - srcCtxt.rollbackTransaction(); - srcCtxt.closeContext(); - } -// dstCtxt.closeContext(); - } - } - - @Override - public void doRollback(ReplicationModel model, - TopiaEntityIdsMap data, - List<ReplicationNode> nodes, - TopiaContext dstCtxt) throws Exception { - if (nodes.isEmpty()) { - - // aucun noeud de réplication commités - return; - } - - TopiaContextImplementor srcCtxt; - - TopiaContext tx; - - boolean needTransaction = true; - - log.info("Will rollback " + nodes.size() + " nodes..."); - - for (ReplicationNode node : nodes) { - - log.info("Rollback node " + node); - srcCtxt = (TopiaContextImplementor) context.beginTransaction(); - - if (needTransaction) { - tx = dstCtxt.beginTransaction(); - } else { - tx = dstCtxt; - } - try { - doRollbackNode(node, srcCtxt, tx, data); - } catch (Exception e) { - - // un erreur est survenu sur le noeud de réplication - // on rollback la transaction de ce noeud - - tx.rollbackTransaction(); - - } finally { - srcCtxt.rollbackTransaction(); - srcCtxt.closeContext(); - - if (needTransaction) { - // on doit fermer la transaction car on l'a ouverte dans - // cette méthode, sinon c'est de la responsabilite du - // code appellant - tx.closeContext(); - } - } - - } - } - - //-------------------------------------------------------------------------- - //-- TopiaReplicationImplementor implementation ---------------------------- - //-------------------------------------------------------------------------- - - @Override - public ReplicationModel createModel(TopiaEntityEnum[] contracts, - String... topiaIds) - throws TopiaException { - - Set<Class<? extends TopiaEntity>> detectTypes = - detectTypes(contracts, topiaIds); - ReplicationModel model = - new ReplicationModel(contracts, detectTypes, topiaIds); - return model; - } - - @Override - public ReplicationModel createModelWithComputedOrder( - TopiaEntityEnum[] contracts, String... topiaIds) - throws TopiaException { - ReplicationModel model = - new ReplicationModel(contracts, false, topiaIds); - return model; - } - - @Override - public ReplicationModel createModelForAll(TopiaEntityEnum[] contracts) - throws TopiaException { - ReplicationModel model = new ReplicationModel(contracts, true); - return model; - } - - @Override - public ReplicationModel initModel(ReplicationModel model, - boolean computeOrder) - throws TopiaException { - checkNotNull("initModel", "model", model); - - model.detectAssociations(); - model.detectDirectDependencies(); - if (computeOrder) { - model.detectShell(); - model.detectDependencies(); - } - model.detectObjectsToDettach(); - model.detectOperations(); - return model; - } - - @Override - public TopiaReplicationOperation getOperation( - Class<? extends TopiaReplicationOperation> operationClass) { - checkNotNull("getOperation", "operationClass", operationClass); - - if (operations == null) { - throw new IllegalStateException("service was not init!"); - } - TopiaReplicationOperation result = null; - - for (TopiaReplicationOperation op : operations) { - if (operationClass.isAssignableFrom(op.getClass())) { - result = op; - break; - } - } - return result; - } - - @Override - public void createOperation(ReplicationModel model, - TopiaEntityEnum type, - ReplicationOperationPhase phase, - Class<? extends TopiaReplicationOperation> operationClass, - Object... parameters) { - - checkNotNull("createOperation", "model", model); - checkNotNull("createOperation", "type", type); - checkNotNull("createOperation", "phase", phase); - checkNotNull("createOperation", "operationClass", operationClass); - - TopiaReplicationOperation operation = getOperation(operationClass); - - if (operation == null) { - throw new IllegalArgumentException( - _("topia.replication.engine.error.unkown.operation", - operationClass.getSimpleName(), - Arrays.toString(operations)) - ); - } - - ReplicationNode node = model.getNode(type); - if (node == null) { - throw new IllegalArgumentException( - _("topia.replication.engine.error.unkown.owner.node", - type, - operationClass.getSimpleName(), - model.getNodes()) - ); - } - operation.register(model, node, phase, parameters); - } - - @Override - public Set<Class<? extends TopiaEntity>> detectTypes( - TopiaEntityEnum[] contracts, String... ids) throws TopiaException { - TopiaContext ctxt = context.beginTransaction(); - try { - TopiaEntity[] entities = getEntities(ctxt, ids); - - // on detecte tous les types connus pour les entites données - Set<Class<? extends TopiaEntity>> types = - TopiaEntityHelper.detectTypes(contracts, entities); - - if (log.isDebugEnabled()) { - log.debug("for type : " + entities.getClass()); - for (Class<? extends TopiaEntity> k : types) { - log.debug(k); - } - } - return types; - } finally { - ctxt.closeContext(); - } - } - - @Override - public TopiaEntityIdsMap getIds(ReplicationModel model, - TopiaContextImplementor srcCtxt) - throws TopiaException { - - TopiaEntityIdsMap data; - - // on recupere les objets a repliquer par type - if (model.isReplicateAll()) { - - // on recupere pour chaque type tous les ids des entites a repliquer - data = new TopiaEntityIdsMap(); - for (TopiaEntityEnum e : model.getContracts()) { - List<String> ids = srcCtxt.getDAO(e.getContract()).findAllIds(); - data.put(e.getContract(), ids); - } - } else { - - // on recupere les entites specifies a repliquer - TopiaEntity[] entities = getEntities(srcCtxt, - model.getTopiaIds() - ); - - // on calcule toutes les ids des entites a repliquer - data = TopiaEntityHelper.detectEntityIds(model.getContracts(), - model.getTypes(), - entities - ); - } - return data; - } - - @Override - public void doReplicateNode( - ReplicationNode node, - TopiaContext srcCtxt, - TopiaContext dstCtxt, - TopiaEntityIdsMap data, - List<ReplicationNode> treated) throws Exception { - - // on trie toujours les operations a realiser selon leur phase - // (avant ou apres la duplication) - node.sortOperations(); - - List<ReplicationOperationDef> operationDefs = node.getOperations(); - - if (operationDefs.isEmpty()) { - log.info("skip node " + node + " - no operation detected."); - } else { - - log.info("start for " + node + " : " + operationDefs.size() + - " operation(s)"); - - List<String> nodeEntityIds = - data.get(node.getContract().getContract()); - - if (log.isInfoEnabled()) { - log.info("will replicate on " + nodeEntityIds.size() + - " entity(ies)"); - } - if (log.isDebugEnabled()) { - for (String id : nodeEntityIds) { - log.debug(id); - } - } - - List<? extends TopiaEntity> nodeEntities = getEntitiesList( - srcCtxt, - nodeEntityIds.toArray(new String[nodeEntityIds.size()]) - ); - - for (ReplicationOperationDef operationDef : operationDefs) { - - log.info("start " + operationDef); - - TopiaReplicationOperation operation = - getOperation(operationDef.getOperationClass()); - - operation.run(operationDef, - (TopiaContextImplementor) srcCtxt, - (TopiaContextImplementor) dstCtxt, - nodeEntities, - data - ); - - } - // on rollback le context source (car on a peut-etre modifie - // des associations ou des dependances mais on ne veut rien - // retenir au niveau d'hibernate, sinon on s'expose a des erreurs - // lorsque l'on veut recharger des objets dans le context...) - srcCtxt.rollbackTransaction(); - } - - treated.add(node); - } - - - @Override - public void doRollbackNode( - ReplicationNode node, - TopiaContext srcCtxt, - TopiaContext dstCtxt, - TopiaEntityIdsMap data) throws Exception { - - // on trie toujours les operations a realiser selon leur phase - // (avant ou apres la duplication) - node.sortOperations(); - - List<ReplicationOperationDef> operationDefs = node.getOperations(); - - if (operationDefs.isEmpty()) { - log.info("skip node " + node + " - no operation detected."); - } else { - - log.info("start for " + node + " : " + operationDefs.size() + - " operation(s)"); - - List<String> nodeEntityIds = - data.get(node.getContract().getContract()); - if (log.isInfoEnabled()) { - log.info("will replicate on " + nodeEntityIds.size() + - " entity(ies)"); - } - if (log.isDebugEnabled()) { - for (String id : nodeEntityIds) { - log.debug(id); - } - } - - List<? extends TopiaEntity> nodeEntities = getEntitiesList( - srcCtxt, - nodeEntityIds.toArray(new String[nodeEntityIds.size()]) - ); - - for (ReplicationOperationDef operationDef : operationDefs) { - - log.info("start " + operationDef); - - TopiaReplicationOperation operation = - getOperation(operationDef.getOperationClass()); - - operation.rollback(operationDef, - (TopiaContextImplementor) srcCtxt, - (TopiaContextImplementor) dstCtxt, - nodeEntities, - data - ); - - } - // on rollback le context source (car on a peut-etre modifie - // des associations ou des dependances mais on ne veut rien - // retenir au niveau d'hibernate, sinon on s'expose a des erreurs - // lorsque l'on veut recharger des objets dans le context...) - srcCtxt.rollbackTransaction(); - } - } - - @SuppressWarnings({"unchecked"}) - public static <E extends TopiaEntity> List<E> getEntities( - TopiaContextImplementor srcCtxt, - List<E> entityList, - boolean canBeNull) throws TopiaException { - List<E> srcList = new ArrayList<E>(entityList.size()); - for (E e : entityList) { - E e2 = (E) srcCtxt.findByTopiaId(e.getTopiaId()); - if (e2 == null && !canBeNull) { -// if (!canBeNull) { -// throw new IllegalStateException( -// "topia.replication.engine.error.entity.must.exists"); -// } - continue; - } - srcList.add(e2); - } - return srcList; - } - - public static TopiaEntity[] getEntities(TopiaContext srcCtxt, - String... entityList) - throws TopiaException { - TopiaEntity[] srcList = new TopiaEntity[entityList.length]; - int index = 0; - for (String id : entityList) { - TopiaEntity e2 = srcCtxt.findByTopiaId(id); - srcList[index++] = e2; - } - return srcList; - } - - public static List<? extends TopiaEntity> getEntitiesList( - TopiaContext srcCtxt, - String... entityList) throws TopiaException { - List<TopiaEntity> srcList = new ArrayList<TopiaEntity>(entityList.length); - for (String id : entityList) { - TopiaEntity e2 = srcCtxt.findByTopiaId(id); - srcList.add(e2); - } - return srcList; - } - - public static void checkNotNull(String methodName, - String parameterName, - Object value) { - if (value == null) { - throw new NullPointerException( - _("topia.replication.engine.error.null.param", - parameterName, methodName)); - } - } - - public static void checkParameters(Class<?>[] paramsType, - Object... params) { - checkSize(paramsType.length, params); - for (int i = 0, j = paramsType.length; i < j; i++) { - checkType(paramsType, i, params); - } - } - - public static void checkSize(int size, Object[] params) { - if (params.length != size) { - throw new IllegalArgumentException( - "l'operation requiere " + size + " parametres mais en a " + - params.length); - } - } - - public static void checkType(Class<?>[] paramsType, - int index, - Object[] params) { - Class<?> requiredType = paramsType[index]; - Object value = params[index]; - if (value == null) { - throw new IllegalArgumentException( - "le parametre de positiion" + index + " est null!"); - } - Class<?> foundType = value.getClass(); - - if (!requiredType.isAssignableFrom(foundType)) { - throw new IllegalArgumentException( - "le paremetre de position " + index + - " requiere un parametre de type " + requiredType + - " mais est de type " + foundType); - } - } -} Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationImplementor.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationImplementor.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationImplementor.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -50,12 +50,17 @@ import java.util.Set; /** - * Class used internaly in framework, when you want implement new replication - * engin, you must used this interface + * Class <b>previously</b> used internaly in framework, when you wanted + * to implement new replication engine. + * <p/> + * Now we are using a {@link TopiaReplicationModelBuilderImpl} insde the implemented + * service. * * @author tchemit <chemit@codelutin.com> * @since 2.2.0 + * @deprecated since 2.4.3, no more need of it, prefer use a {@link TopiaReplicationModelBuilderImpl}. */ +@Deprecated public interface TopiaReplicationImplementor extends TopiaReplicationService { /** @@ -171,5 +176,5 @@ ReplicationNode node, TopiaContext srcCtxt, TopiaContext dstCtxt, - TopiaEntityIdsMap data) throws Exception; + TopiaEntityIdsMap data) throws Exception; } Added: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilder.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilder.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilder.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,146 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.topia.replication; + +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaEntityEnum; +import org.nuiton.topia.replication.model.ReplicationModel; +import org.nuiton.topia.replication.model.ReplicationOperationPhase; + +import java.util.Set; + +/** + * Helper to create {@link ReplicationModel}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.4.3 + */ +public interface TopiaReplicationModelBuilder { + + TopiaReplicationOperationProvider getOperationProvider(); + + TopiaReplicationOperation getOperation(Class<? extends TopiaReplicationOperation> operationClass); + + TopiaReplicationOperation[] getOperations(); + + /** + * Creation d'un modele de replication non initialise. + * + * @param context topia context on which entities are loaded + * @param contracts le contrats d'entites autorises + * @param topiaIds les ids des entites a repliquer + * @return le modele instancie mais non initialise + * @throws TopiaException pour toute erreur + */ + ReplicationModel createModel(TopiaContext context, + TopiaEntityEnum[] contracts, + String... topiaIds) throws TopiaException; + + /** + * Creation d'un modele de replication non initialise avec un ordre fixe + * (celui des contrats donnés). + * + * @param contracts le contrats d'entites autorises + * @param topiaIds les ids des entities a repliquer + * @return le modele instancie mais non initialise + * @throws TopiaException pour toute erreur + */ + ReplicationModel createModelWithComputedOrder( + TopiaEntityEnum[] contracts, + String... topiaIds) throws TopiaException; + + /** + * Creation d'un modele de replication (en mode tout dupliquer) non initialise. + * + * @param contracts le contrats d'entites autorises + * @return le modele instancie mais non initialise + * @throws TopiaException pour toute erreur + */ + ReplicationModel createModelForAll(TopiaEntityEnum[] contracts) + throws TopiaException; + + + ReplicationModel prepare(TopiaContext context, + TopiaEntityEnum[] contracts, + String... entities) throws TopiaException; + + /** + * Prepare le modele de replication pour toutes les entites des types + * donnes. + * <p/> + * La méthode calcule l'ordre de replication des données. + * <p/> + * Actuellement, on n'est pas capable de calculer l'ordre si le graphe des + * entités contient des cycles. + * <p/> + * 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 + */ + ReplicationModel prepareForAll(TopiaEntityEnum[] contracts) throws TopiaException; + + /** + * Prepare le modele de replication pour les entites données en ne faisant + * pas de calcul sur l'ordre des entités à répliquer. + * <p/> + * L'ordre des types donnees sera celui utilisé. + * + * @param contracts les contrats a repliquer (dans l'ordre donnée) + * @param topiaIds les ids des entites a repliquer + * @return le model de replication initialise + * @throws TopiaException pour toute erreur recontree + */ + ReplicationModel prepareWithComputedOrder(TopiaEntityEnum[] contracts, + String... topiaIds) throws TopiaException; + + Set<Class<? extends TopiaEntity>> detectTypes( + TopiaContext context, + TopiaEntityEnum[] contracts, String... ids) throws TopiaException; + + ReplicationModel initModel(ReplicationModel model, + boolean computeOrder) + throws TopiaException; + + void addBeforeOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters); + + void addAfterOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters); + + void createOperation( + ReplicationModel model, + TopiaEntityEnum type, + ReplicationOperationPhase phase, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters); +} Added: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilderImpl.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilderImpl.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationModelBuilderImpl.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,258 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +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; + +import static org.nuiton.i18n.I18n._; + +/** + * Default implementation of {@link TopiaReplicationModelBuilder}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.4.3 + */ +public class TopiaReplicationModelBuilderImpl implements TopiaReplicationModelBuilder { + + /** Logger */ + private static final Log log = + LogFactory.getLog(TopiaReplicationModelBuilderImpl.class); + + protected TopiaReplicationOperationProvider operationProvider; + + @Override + public TopiaReplicationOperationProvider getOperationProvider() { + if (operationProvider == null) { + operationProvider = new TopiaReplicationOperationProviderImpl(); + } + return operationProvider; + } + + @Override + public TopiaReplicationOperation getOperation(Class<? extends TopiaReplicationOperation> operationClass) { + return getOperationProvider().getOperation(operationClass); + } + + @Override + public TopiaReplicationOperation[] getOperations() { + return getOperationProvider().getOperations(); + } + + + @Override + public ReplicationModel createModel(TopiaContext context, + TopiaEntityEnum[] contracts, + String... topiaIds) + throws TopiaException { + + Set<Class<? extends TopiaEntity>> detectTypes = + detectTypes(context, contracts, topiaIds); + ReplicationModel model = + new ReplicationModel(contracts, detectTypes, topiaIds); + return model; + } + + + @Override + public ReplicationModel createModelWithComputedOrder( + TopiaEntityEnum[] contracts, + String... topiaIds) + throws TopiaException { + ReplicationModel model = + new ReplicationModel(contracts, false, topiaIds); + return model; + } + + + @Override + public ReplicationModel createModelForAll(TopiaEntityEnum[] contracts) + throws TopiaException { + ReplicationModel model = new ReplicationModel(contracts, true); + return model; + } + + @Override + public void createOperation( + ReplicationModel model, + TopiaEntityEnum type, + ReplicationOperationPhase phase, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) { + + TopiaEntityHelper.checkNotNull("createOperation", "provider", operationProvider); + TopiaEntityHelper.checkNotNull("createOperation", "model", model); + TopiaEntityHelper.checkNotNull("createOperation", "type", type); + TopiaEntityHelper.checkNotNull("createOperation", "phase", phase); + TopiaEntityHelper.checkNotNull("createOperation", "operationClass", operationClass); + + TopiaReplicationOperation operation = operationProvider.getOperation(operationClass); + + if (operation == null) { + throw new IllegalArgumentException( + _("topia.replication.engine.error.unkown.operation", + operationClass.getSimpleName(), + Arrays.toString(operationProvider.getOperations())) + ); + } + + ReplicationNode node = model.getNode(type); + if (node == null) { + throw new IllegalArgumentException( + _("topia.replication.engine.error.unkown.owner.node", + type, + operationClass.getSimpleName(), + model.getNodes()) + ); + } + operation.register(model, node, phase, parameters); + } + + + @Override + public ReplicationModel prepare(TopiaContext context, + TopiaEntityEnum[] contracts, + String... entities) throws TopiaException { + ReplicationModel model = + createModel(context, contracts, entities); + initModel(model, true); + return model; + } + + + @Override + public ReplicationModel prepareForAll(TopiaEntityEnum[] contracts) throws TopiaException { + ReplicationModel model = createModelForAll(contracts); + initModel(model, true); + return model; + } + + + @Override + public ReplicationModel prepareWithComputedOrder(TopiaEntityEnum[] contracts, + String... topiaIds) throws TopiaException { + ReplicationModel model = + createModelWithComputedOrder(contracts, topiaIds); + initModel(model, false); + return model; + } + + @Override + public Set<Class<? extends TopiaEntity>> detectTypes(TopiaContext context, + TopiaEntityEnum[] contracts, + String... ids) throws TopiaException { + + TopiaContext ctxt = context.beginTransaction(); + try { + TopiaEntity[] entities = TopiaEntityHelper.getEntities(ctxt, ids); + + // on detecte tous les types connus pour les entites données + Set<Class<? extends TopiaEntity>> types = + TopiaEntityHelper.detectTypes(contracts, entities); + + if (log.isDebugEnabled()) { + log.debug("for type : " + entities.getClass()); + for (Class<? extends TopiaEntity> k : types) { + log.debug(k); + } + } + return types; + } finally { + ctxt.closeContext(); + } + } + + @Override + 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; + } + + + /** + * 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 + */ + @Override + public void addBeforeOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> 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 + */ + @Override + public void addAfterOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) { + createOperation( + model, + type, + ReplicationOperationPhase.after, + operationClass, + parameters + ); + } +} Added: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProvider.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProvider.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProvider.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,53 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.topia.replication; + +import java.util.ServiceLoader; + +/** + * Provider of {@link TopiaReplicationOperation}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.4.3 + */ +public interface TopiaReplicationOperationProvider { + + /** + * Obtains all {@link TopiaReplicationOperation} available + * via {@link ServiceLoader}. + * + * @return the array of available operations + */ + TopiaReplicationOperation[] getOperations(); + + /** + * Obtains the instanciated (and initialized) operation of the given type. + * + * @param operationClass type of searched operation + * @return the found operation, or {@code null} if not found. + */ + TopiaReplicationOperation getOperation( + Class<? extends TopiaReplicationOperation> operationClass); +} Added: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProviderImpl.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProviderImpl.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationOperationProviderImpl.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,92 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.persistence.util.TopiaEntityHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +/** + * Default implementation of {@link TopiaReplicationOperationProvider}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.4.3 + */ +public class TopiaReplicationOperationProviderImpl implements TopiaReplicationOperationProvider { + + /** Logger */ + private static final Log log = + LogFactory.getLog(TopiaReplicationOperationProviderImpl.class); + + /** + * la liste des operations disponibles (chargee automatiquement via un + * ServiceLoader sur le contract {@link TopiaReplicationOperation}) + */ + protected TopiaReplicationOperation[] operations; + + @Override + public TopiaReplicationOperation[] getOperations() { + if (operations == null) { + // chargement des operations disponibles une seule fois + + ServiceLoader<TopiaReplicationOperation> loader = + ServiceLoader.load(TopiaReplicationOperation.class); + + List<TopiaReplicationOperation> operations = + new ArrayList<TopiaReplicationOperation>(); + + for (TopiaReplicationOperation op : loader) { + if (log.isDebugEnabled()) { + log.debug("detected operation " + op); + } + operations.add(op); + } + this.operations = operations.toArray( + new TopiaReplicationOperation[operations.size()]); + } + return operations; + } + + @Override + public TopiaReplicationOperation getOperation( + Class<? extends TopiaReplicationOperation> operationClass) { + + TopiaEntityHelper.checkNotNull("getOperation", "operationClass", + operationClass); + TopiaReplicationOperation result = null; + + for (TopiaReplicationOperation op : getOperations()) { + if (operationClass.isAssignableFrom(op.getClass())) { + result = op; + break; + } + } + return result; + } +} Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationService.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationService.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationService.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -22,18 +22,6 @@ * <http://www.gnu.org/licenses/lgpl-3.0.html>. * #L% */ - -/* * - * IndexEngin.java - * - * Created: 8 oct. 06 17:15:00 - * - * @author poussin <poussin@codelutin.com> - * @version $Revision$ - * - * Last update: $Date$ - * by : $Author$ - */ package org.nuiton.topia.replication; import org.nuiton.topia.TopiaContext; @@ -72,6 +60,8 @@ /** Nom du service topia */ String TOPIA_SERVICE_NAME = "topia.service.replication"; + TopiaReplicationModelBuilder getModelBuilder(); + /** * Prepare le modele de replication pour les entites dans les topiaIds sont * donnes. Copied: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationServiceImpl.java (from rev 2098, trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/ReplicationEngine.java) =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationServiceImpl.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationServiceImpl.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,576 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.framework.TopiaContextImplementor; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaEntityEnum; +import org.nuiton.topia.persistence.util.TopiaEntityHelper; +import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; +import org.nuiton.topia.replication.model.ReplicationModel; +import org.nuiton.topia.replication.model.ReplicationNode; +import org.nuiton.topia.replication.model.ReplicationOperationDef; + +import java.util.ArrayList; +import java.util.List; + +/** + * Implantation du service de replication. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.2.0 + */ +public class TopiaReplicationServiceImpl implements TopiaReplicationService { + + /** Logger */ + private static final Log log = LogFactory.getLog(TopiaReplicationServiceImpl.class); + + /** le contexte sur la base source de la replication */ + protected TopiaContextImplementor context; + + protected TopiaReplicationModelBuilder modelBuilder; + + //-------------------------------------------------------------------------- + //-- TopiaService implementation ------------------------------------------- + //-------------------------------------------------------------------------- + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + @Override + public Class<?>[] getPersistenceClasses() { + // pas de classes persistentes pour ce service + return null; + } + + @Override + public boolean preInit(TopiaContextImplementor context) { + // nothing to init + return true; + } + + @Override + public boolean postInit(TopiaContextImplementor context) { + // set the incoming root context from topia + this.context = context; + //TODO avoir un objet pour lire les contrainte de resolution de cycle + //TODO sur les dependances (par exemple, une dependance marquee comme + // non nulle : ne peut jamais etre dettache, alors que dans le cas + // contraire on peut dettacher la dependance + // Cela permet de traiter plus de cas... + + //Properties prop = context.getConfig(); + return true; + } + + //-------------------------------------------------------------------------- + //-- TopiaReplicationService implementation -------------------------------- + //-------------------------------------------------------------------------- + + @Override + public ReplicationModel prepare(TopiaEntityEnum[] contracts, + String... entities) throws TopiaException { + ReplicationModel model = getModelBuilder().prepare(context, contracts, entities); + return model; +// ReplicationModel model = +// createModel(contracts, entities); +// +// initModel(model, true); +// +// return model; + } + + @Override + public ReplicationModel prepareForAll(TopiaEntityEnum[] contracts) throws TopiaException { + ReplicationModel model = getModelBuilder().prepareForAll(contracts); + return model; +// ReplicationModel model = createModelForAll(contracts); +// +// initModel(model, true); +// +// return model; + } + + @Override + public ReplicationModel prepareWithComputedOrder(TopiaEntityEnum[] contracts, + String... topiaIds) throws TopiaException { + ReplicationModel model = getModelBuilder().prepareWithComputedOrder(contracts); + return model; +// ReplicationModel model = createModelWithComputedOrder(contracts, topiaIds); +// +// initModel(model, false); +// +// return model; + } + + @Override + public void addBeforeOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) { + getModelBuilder().addBeforeOperation(model, type, operationClass, parameters); +// createOperation(model, +// type, +// ReplicationOperationPhase.before, +// operationClass, +// parameters +// ); + } + + @Override + public void addAfterOperation(ReplicationModel model, + TopiaEntityEnum type, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) { + getModelBuilder().addAfterOperation(model, type, operationClass, parameters); +// createOperation(model, +// type, +// ReplicationOperationPhase.after, +// operationClass, +// parameters +// ); + } + + @Override + public void doReplicate(ReplicationModel model, + TopiaContext dstCtxt) throws Exception { + + TopiaEntityHelper.checkNotNull("doReplicate", "model", model); + TopiaEntityHelper.checkNotNull("doReplicate", "dstCtxt", dstCtxt); + + TopiaContextImplementor srcCtxt = null; + + TopiaEntityIdsMap data = null; + + // keep the list of treated nodes (to roolback them if something + // is wrong). + List<ReplicationNode> treated = new ArrayList<ReplicationNode>(); + try { + + srcCtxt = (TopiaContextImplementor) context.beginTransaction(); + + data = getIds(model, srcCtxt); + + srcCtxt.closeContext(); + + model.adjustOperations(data); + + //FIXME tchemit 2077-07-26, should use next line when + // http://nuiton.org/issues/show/779 is closed + boolean needTransaction = true; +// boolean needTransaction = ((TopiaContextImplementor) dstCtxt).getRootContext().equals(dstCtxt); + + TopiaContext tx; + + for (ReplicationNode node : model.getOrder()) { + + srcCtxt = (TopiaContextImplementor) context.beginTransaction(); + + if (needTransaction) { + tx = dstCtxt.beginTransaction(); + } else { + tx = dstCtxt; + } + try { + doReplicateNode(node, srcCtxt, tx, data, treated); + } catch (Exception e) { + + // un erreur est survenu sur le noeud de réplication + // on rollback la transaction de ce noeud + try { + tx.rollbackTransaction(); + } finally { + + // on revert les noeuds deja commite + doRollback(model, data, treated, dstCtxt); + } + + throw e; + } finally { + srcCtxt.closeContext(); + if (needTransaction) { + // on doit fermer la transaction car on l'a ouverte dans + // cette méthode, sinon c'est de la responsabilite du + // code appellant + tx.closeContext(); + } + } + } +// } catch (Exception e) { +// dstCtxt.rollbackTransaction(); +// throw e; + } finally { + if (data != null) { + data.clear(); + } + if (treated != null) { + treated.clear(); + } + // on ne doit jamais commiter sur la base source + if (srcCtxt != null && !srcCtxt.isClosed()) { + srcCtxt.rollbackTransaction(); + srcCtxt.closeContext(); + } +// dstCtxt.closeContext(); + } + } + + @Override + public void doRollback(ReplicationModel model, + TopiaEntityIdsMap data, + List<ReplicationNode> nodes, + TopiaContext dstCtxt) throws Exception { + if (nodes.isEmpty()) { + + // aucun noeud de réplication commités + return; + } + + TopiaContextImplementor srcCtxt; + + TopiaContext tx; + + boolean needTransaction = true; + + log.info("Will rollback " + nodes.size() + " nodes..."); + + for (ReplicationNode node : nodes) { + + log.info("Rollback node " + node); + srcCtxt = (TopiaContextImplementor) context.beginTransaction(); + + if (needTransaction) { + tx = dstCtxt.beginTransaction(); + } else { + tx = dstCtxt; + } + try { + doRollbackNode(node, srcCtxt, tx, data); + } catch (Exception e) { + + // un erreur est survenu sur le noeud de réplication + // on rollback la transaction de ce noeud + + tx.rollbackTransaction(); + + } finally { + srcCtxt.rollbackTransaction(); + srcCtxt.closeContext(); + + if (needTransaction) { + // on doit fermer la transaction car on l'a ouverte dans + // cette méthode, sinon c'est de la responsabilite du + // code appellant + tx.closeContext(); + } + } + + } + } + + @Override + public TopiaReplicationModelBuilder getModelBuilder() { + if (modelBuilder == null) { + modelBuilder = new TopiaReplicationModelBuilderImpl(); + } + return modelBuilder; + } + + //-------------------------------------------------------------------------- + //-- TopiaReplicationImplementor implementation ---------------------------- + //-------------------------------------------------------------------------- + +// @Override +// public ReplicationModel createModel(TopiaEntityEnum[] contracts, +// String... topiaIds) +// throws TopiaException { +// +// Set<Class<? extends TopiaEntity>> detectTypes = +// detectTypes(contracts, topiaIds); +// ReplicationModel model = +// new ReplicationModel(contracts, detectTypes, topiaIds); +// return model; +// } +// +// @Override +// public ReplicationModel createModelWithComputedOrder( +// TopiaEntityEnum[] contracts, String... topiaIds) +// throws TopiaException { +// ReplicationModel model = +// new ReplicationModel(contracts, false, topiaIds); +// return model; +// } +// +// @Override +// public ReplicationModel createModelForAll(TopiaEntityEnum[] contracts) +// throws TopiaException { +// ReplicationModel model = new ReplicationModel(contracts, true); +// return model; +// } +// +// @Override +// public ReplicationModel initModel(ReplicationModel model, +// boolean computeOrder) +// throws TopiaException { +// checkNotNull("initModel", "model", model); +// +// model.detectAssociations(); +// model.detectDirectDependencies(); +// if (computeOrder) { +// model.detectShell(); +// model.detectDependencies(); +// } +// model.detectObjectsToDettach(); +// model.detectOperations(); +// return model; +// } +// +// @Override +// public TopiaReplicationOperation getOperation( +// Class<? extends TopiaReplicationOperation> operationClass) { +// checkNotNull("getOperation", "operationClass", operationClass); +// +// if (operations == null) { +// throw new IllegalStateException("service was not init!"); +// } +// TopiaReplicationOperation result = null; +// +// for (TopiaReplicationOperation op : operations) { +// if (operationClass.isAssignableFrom(op.getClass())) { +// result = op; +// break; +// } +// } +// return result; +// } +// +// @Override +// public void createOperation(ReplicationModel model, +// TopiaEntityEnum type, +// ReplicationOperationPhase phase, +// Class<? extends TopiaReplicationOperation> operationClass, +// Object... parameters) { +// +// checkNotNull("createOperation", "model", model); +// checkNotNull("createOperation", "type", type); +// checkNotNull("createOperation", "phase", phase); +// checkNotNull("createOperation", "operationClass", operationClass); +// +// TopiaReplicationOperation operation = getOperation(operationClass); +// +// if (operation == null) { +// throw new IllegalArgumentException( +// _("topia.replication.engine.error.unkown.operation", +// operationClass.getSimpleName(), +// Arrays.toString(operations)) +// ); +// } +// +// ReplicationNode node = model.getNode(type); +// if (node == null) { +// throw new IllegalArgumentException( +// _("topia.replication.engine.error.unkown.owner.node", +// type, +// operationClass.getSimpleName(), +// model.getNodes()) +// ); +// } +// operation.register(model, node, phase, parameters); +// } + +// @Override + + public TopiaEntityIdsMap getIds(ReplicationModel model, + TopiaContextImplementor srcCtxt) + throws TopiaException { + + TopiaEntityIdsMap data; + + // on recupere les objets a repliquer par type + if (model.isReplicateAll()) { + + // on recupere pour chaque type tous les ids des entites a repliquer + data = new TopiaEntityIdsMap(); + for (TopiaEntityEnum e : model.getContracts()) { + List<String> ids = srcCtxt.getDAO(e.getContract()).findAllIds(); + data.put(e.getContract(), ids); + } + } else { + + // on recupere les entites specifies a repliquer + TopiaEntity[] entities = TopiaEntityHelper.getEntities(srcCtxt, + model.getTopiaIds() + ); + + // on calcule toutes les ids des entites a repliquer + data = TopiaEntityHelper.detectEntityIds(model.getContracts(), + model.getTypes(), + entities + ); + } + return data; + } + +// protected void checkServiceIsInit() { +// if (modelBuilder == null) { +// throw new IllegalStateException("service was not init!"); +// } +// } + +// @Override + + public void doReplicateNode( + ReplicationNode node, + TopiaContext srcCtxt, + TopiaContext dstCtxt, + TopiaEntityIdsMap data, + List<ReplicationNode> treated) throws Exception { + + // on trie toujours les operations a realiser selon leur phase + // (avant ou apres la duplication) + node.sortOperations(); + + List<ReplicationOperationDef> operationDefs = node.getOperations(); + + if (operationDefs.isEmpty()) { + log.info("skip node " + node + " - no operation detected."); + } else { + + log.info("start for " + node + " : " + operationDefs.size() + + " operation(s)"); + + List<String> nodeEntityIds = + data.get(node.getContract().getContract()); + + if (log.isInfoEnabled()) { + log.info("will replicate on " + nodeEntityIds.size() + + " entity(ies)"); + } + if (log.isDebugEnabled()) { + for (String id : nodeEntityIds) { + log.debug(id); + } + } + + List<? extends TopiaEntity> nodeEntities = TopiaEntityHelper.getEntitiesList( + srcCtxt, + nodeEntityIds.toArray(new String[nodeEntityIds.size()]) + ); + + for (ReplicationOperationDef operationDef : operationDefs) { + + log.info("start " + operationDef); + + TopiaReplicationOperation operation = + getModelBuilder().getOperation(operationDef.getOperationClass()); + + operation.run(operationDef, + (TopiaContextImplementor) srcCtxt, + (TopiaContextImplementor) dstCtxt, + nodeEntities, + data + ); + + } + // on rollback le context source (car on a peut-etre modifie + // des associations ou des dependances mais on ne veut rien + // retenir au niveau d'hibernate, sinon on s'expose a des erreurs + // lorsque l'on veut recharger des objets dans le context...) + srcCtxt.rollbackTransaction(); + } + + treated.add(node); + } + + +// @Override + + public void doRollbackNode( + ReplicationNode node, + TopiaContext srcCtxt, + TopiaContext dstCtxt, + TopiaEntityIdsMap data) throws Exception { + + // on trie toujours les operations a realiser selon leur phase + // (avant ou apres la duplication) + node.sortOperations(); + + List<ReplicationOperationDef> operationDefs = node.getOperations(); + + if (operationDefs.isEmpty()) { + log.info("skip node " + node + " - no operation detected."); + } else { + + log.info("start for " + node + " : " + operationDefs.size() + + " operation(s)"); + + List<String> nodeEntityIds = + data.get(node.getContract().getContract()); + if (log.isInfoEnabled()) { + log.info("will replicate on " + nodeEntityIds.size() + + " entity(ies)"); + } + if (log.isDebugEnabled()) { + for (String id : nodeEntityIds) { + log.debug(id); + } + } + + List<? extends TopiaEntity> nodeEntities = TopiaEntityHelper.getEntitiesList( + srcCtxt, + nodeEntityIds.toArray(new String[nodeEntityIds.size()]) + ); + + for (ReplicationOperationDef operationDef : operationDefs) { + + log.info("start " + operationDef); + + TopiaReplicationOperation operation = + getModelBuilder().getOperation(operationDef.getOperationClass()); + + operation.rollback(operationDef, + (TopiaContextImplementor) srcCtxt, + (TopiaContextImplementor) dstCtxt, + nodeEntities, + data + ); + + } + // on rollback le context source (car on a peut-etre modifie + // des associations ou des dependances mais on ne veut rien + // retenir au niveau d'hibernate, sinon on s'expose a des erreurs + // lorsque l'on veut recharger des objets dans le context...) + srcCtxt.rollbackTransaction(); + } + } + +} Property changes on: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/TopiaReplicationServiceImpl.java ___________________________________________________________________ Added: svn:keywords + HeadURL Id Date Revision Author Deleted: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/Link.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/Link.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/Link.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,116 +0,0 @@ -/* - * #%L - * ToPIA :: Service Replication - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 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 - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.topia.replication.model; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * Pour definir un lien entre deux entites (deux noeuds de replication). - * - * @author tchemit <chemit@codelutin.com> - * @since 2.2.0 - */ -public class Link { - - /** le noeud source du lien */ - protected final ReplicationNode source; - - /** le noeud destination du lien */ - protected final ReplicationNode target; - - /** - * liste des noeuds requis. - * <p/> - * TODO tchemit 2010-08-14 Expliquer à quoi ça sert vraiment... - */ - protected final Set<ReplicationNode> requires; - - /** nom du lien */ - protected final String name; - - /** drapeau positionné à {@code true} lorsque le lien est une association. */ - protected final boolean association; - - public Link(ReplicationNode source, - ReplicationNode target, - String name, - boolean association) { - this.source = source; - this.target = target; - this.name = name; - this.association = association; - Set<ReplicationNode> tmpSet = new HashSet<ReplicationNode>(); - tmpSet.add(source); - tmpSet.addAll(source.getAssociations().values()); - tmpSet.addAll(source.getDependencies().values()); - tmpSet.remove(target); - requires = Collections.unmodifiableSet(tmpSet); - } - - public String getName() { - return name; - } - - public ReplicationNode getSource() { - return source; - } - - public ReplicationNode getTarget() { - return target; - } - - public boolean isAssociation() { - return association; - } - - /** - * Teste si on peut reattacher le lien en connaissant l'univers des - * noeuds disponibles. - * <p/> - * On teste si toutes les pre-requis sont disponibles. - * <p/> - * Si oui, on peut reattacher. - * - * @param universe l'univers des noeuds disponibles - * @param currentNode le noeud qui vient d'etre replique - * @return <code>true</code> si on peut reattacher ce lien - */ - public boolean canReattach(Set<ReplicationNode> universe, - ReplicationNode currentNode) { - boolean result = universe.containsAll(requires); - if (result) { - result = currentNode.equals(target) || universe.contains(target); - } - return result; - } - - @Override - public String toString() { - return "<source:" + source + ", target:" + target + ", name:" + name + ", association:" + association + ">"; - } -} Copied: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationLink.java (from rev 2098, trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/Link.java) =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationLink.java (rev 0) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationLink.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,116 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.topia.replication.model; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Pour definir un lien entre deux entites (deux noeuds de replication). + * + * @author tchemit <chemit@codelutin.com> + * @since 2.2.0 + */ +public class ReplicationLink { + + /** le noeud source du lien */ + protected final ReplicationNode source; + + /** le noeud destination du lien */ + protected final ReplicationNode target; + + /** + * liste des noeuds requis. + * <p/> + * TODO tchemit 2010-08-14 Expliquer à quoi ça sert vraiment... + */ + protected final Set<ReplicationNode> requires; + + /** nom du lien */ + protected final String name; + + /** drapeau positionné à {@code true} lorsque le lien est une association. */ + protected final boolean association; + + public ReplicationLink(ReplicationNode source, + ReplicationNode target, + String name, + boolean association) { + this.source = source; + this.target = target; + this.name = name; + this.association = association; + Set<ReplicationNode> tmpSet = new HashSet<ReplicationNode>(); + tmpSet.add(source); + tmpSet.addAll(source.getAssociations().values()); + tmpSet.addAll(source.getDependencies().values()); + tmpSet.remove(target); + requires = Collections.unmodifiableSet(tmpSet); + } + + public String getName() { + return name; + } + + public ReplicationNode getSource() { + return source; + } + + public ReplicationNode getTarget() { + return target; + } + + public boolean isAssociation() { + return association; + } + + /** + * Teste si on peut reattacher le lien en connaissant l'univers des + * noeuds disponibles. + * <p/> + * On teste si toutes les pre-requis sont disponibles. + * <p/> + * Si oui, on peut reattacher. + * + * @param universe l'univers des noeuds disponibles + * @param currentNode le noeud qui vient d'etre replique + * @return <code>true</code> si on peut reattacher ce lien + */ + public boolean canReattach(Set<ReplicationNode> universe, + ReplicationNode currentNode) { + boolean result = universe.containsAll(requires); + if (result) { + result = currentNode.equals(target) || universe.contains(target); + } + return result; + } + + @Override + public String toString() { + return "<source:" + source + ", target:" + target + ", name:" + name + ", association:" + association + ">"; + } +} Property changes on: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationLink.java ___________________________________________________________________ Added: svn:keywords + HeadURL Id Date Revision Author Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationModel.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationModel.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/model/ReplicationModel.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -373,8 +373,8 @@ public void detectOperations() { Set<ReplicationNode> universe = new HashSet<ReplicationNode>(); - Set<Link> links = new HashSet<Link>(); - Set<Link> linksToLoad = new HashSet<Link>(); + Set<ReplicationLink> links = new HashSet<ReplicationLink>(); + Set<ReplicationLink> linksToLoad = new HashSet<ReplicationLink>(); // premiere passe pour recuperer toutes les associations @@ -384,7 +384,7 @@ String name = entry.getKey(); // dans tous les cas, on ajoute un link d'association a reattacher ReplicationNode target = node.getAssociations().get(name); - Link link = new Link(node, target, name, true); + ReplicationLink link = new ReplicationLink(node, target, name, true); if (nodes.containsValue(target)) { // on a trouve une association que l'on doit gerer links.add(link); @@ -400,7 +400,7 @@ if (!TopiaEntity.class.isAssignableFrom(associationPropertyType) || !nodes.containsKey(associationPropertyType)) { - Link link = new Link(node, null, name, true); + ReplicationLink link = new ReplicationLink(node, null, name, true); linksToLoad.add(link); if (log.isDebugEnabled()) { @@ -425,18 +425,18 @@ addPreOperation(node, node, DettachAssociation.class, name); } } - Set<Link> tmpLinks = new HashSet<Link>(); + Set<ReplicationLink> tmpLinks = new HashSet<ReplicationLink>(); // recherche des associations a charger avant replication - for (Link link : linksToLoad) { + for (ReplicationLink link : linksToLoad) { if (node.equals(link.getSource())) { tmpLinks.add(link); } } if (!tmpLinks.isEmpty()) { // on a des associations a charger avant replication - for (Link link : tmpLinks) { + for (ReplicationLink link : tmpLinks) { addPreOperation(node, node, LoadLink.class, link); // ReplicationOperationDef op = new ReplicationOperationDef(ReplicationOperationPhase.before, LoadLink.class, node, link); // node.addOperation(op); @@ -452,7 +452,7 @@ universe.add(node); // operations de reattachement - for (Link link : links) { + for (ReplicationLink link : links) { if (link.canReattach(universe, node)) { // lien reattachable tmpLinks.add(link); @@ -460,7 +460,7 @@ } if (!tmpLinks.isEmpty()) { // on a trouve des liens a reattacher - for (Link link : tmpLinks) { + for (ReplicationLink link : tmpLinks) { addPostOperation(node, node, AttachLink.class, link); // ReplicationOperationDef op = new ReplicationOperationDef(ReplicationOperationPhase.after, AttachLink.class, node, link); // node.addOperation(op); @@ -522,9 +522,9 @@ } protected void addPreOperation(ReplicationNode ownerNode, - ReplicationNode node, - Class<? extends TopiaReplicationOperation> operationClass, - Object... params) { + ReplicationNode node, + Class<? extends TopiaReplicationOperation> operationClass, + Object... params) { addOperation(ownerNode, node, ReplicationOperationPhase.before, operationClass, params); } @@ -536,9 +536,9 @@ } protected void addPostOperation(ReplicationNode ownerNode, - ReplicationNode node, - Class<? extends TopiaReplicationOperation> operationClass, - Object... params) { + ReplicationNode node, + Class<? extends TopiaReplicationOperation> operationClass, + Object... params) { addOperation(ownerNode, node, ReplicationOperationPhase.after, operationClass, params); } Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachAssociation.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachAssociation.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachAssociation.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -33,7 +33,6 @@ import org.nuiton.topia.persistence.util.EntityOperator; import org.nuiton.topia.persistence.util.TopiaEntityHelper; import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; -import org.nuiton.topia.replication.ReplicationEngine; import org.nuiton.topia.replication.TopiaReplicationOperation; import org.nuiton.topia.replication.model.ReplicationModel; import org.nuiton.topia.replication.model.ReplicationNode; @@ -71,13 +70,17 @@ */ public class AttachAssociation implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(AttachAssociation.class); @Override - public void register(ReplicationModel model, ReplicationNode ownerNode, ReplicationOperationPhase phase, Object... parameters) { + public void register(ReplicationModel model, + ReplicationNode ownerNode, + ReplicationOperationPhase phase, + Object... parameters) { - throw new UnsupportedOperationException(_("topia.replication.operation.error.uncreatable", getClass())); + throw new UnsupportedOperationException( + _("topia.replication.operation.error.uncreatable", getClass())); } @Override @@ -91,7 +94,8 @@ Boolean reverse = (Boolean) operationDef.getParameters()[1]; if (log.isDebugEnabled()) { - log.debug("currentNode : " + operationDef.getNode() + " , association name : " + name + " reverse ? " + reverse); + log.debug("currentNode : " + operationDef.getNode() + + " , association name : " + name + " reverse ? " + reverse); } ReplicationNode ownerNode; @@ -137,7 +141,8 @@ if (ownerIds == null || ownerIds.isEmpty()) { // pas de donnees a traiter - log.info(_("topia.replication.attachAssociation.nothing.to.do", ownerOperator)); + log.info(_("topia.replication.attachAssociation.nothing.to.do", + ownerOperator)); return; } @@ -148,13 +153,17 @@ // modifiees (dettachement d'association ou autres) // ils nous faut les entites telles qu'elles sont en base source - ownerEntities = ReplicationEngine.getEntitiesList(srcCtxt, ownerIds.toArray(new String[ownerIds.size()])); + ownerEntities = TopiaEntityHelper.getEntitiesList( + srcCtxt, + ownerIds.toArray(new String[ownerIds.size()]) + ); boolean shouldCommit = false; if (log.isInfoEnabled()) { - log.info("ownerNode : " + ownerNode + " , targetNode : " + cibleNode + ", association : " + name); + log.info("ownerNode : " + ownerNode + " , targetNode : " + + cibleNode + ", association : " + name); } if (log.isDebugEnabled()) { log.debug("owner ids : " + ownerIds); @@ -174,7 +183,8 @@ continue; } if (log.isDebugEnabled()) { - log.debug("will try to attach " + targetEntities.size() + " association(s) '" + name + "' to " + src); + log.debug("will try to attach " + targetEntities.size() + + " association(s) '" + name + "' to " + src); } // l'entite repliquee a laquelle on veut attacher l'association @@ -182,10 +192,16 @@ TopiaEntity dst = dstCtxt.findByTopiaId(src.getTopiaId()); // les association cibles connues pour l'entite sur la base destination - Collection<?> dstTargetEntities = (Collection<?>) ownerOperator.get(name, dst); + Collection<?> dstTargetEntities = (Collection<?>) + ownerOperator.get(name, dst); // les ids des entities deja associees - List<String> dstTargetAssociationsId = dstTargetEntities == null ? Collections.EMPTY_LIST : TopiaEntityHelper.getTopiaIdList((List<? extends TopiaEntity>) dstTargetEntities); + List<String> dstTargetAssociationsId = + dstTargetEntities == null ? + Collections.<String>emptyList() : + TopiaEntityHelper.getTopiaIdList( + (List<? extends TopiaEntity>) dstTargetEntities); + boolean shouldUpdate = false; for (Object a : targetEntities) { @@ -196,7 +212,8 @@ if (dstTargetAssociationsId.contains(assosiationSrc.getTopiaId())) { // deja attache if (log.isDebugEnabled()) { - log.debug("already attached association '" + name + "' : " + assosiationSrc); + log.debug("already attached association '" + name + + "' : " + assosiationSrc); } continue; @@ -204,10 +221,12 @@ // la donnees doit etre attachee - TopiaEntity assosiationDst = dstCtxt.findByTopiaId(assosiationSrc.getTopiaId()); + TopiaEntity assosiationDst = + dstCtxt.findByTopiaId(assosiationSrc.getTopiaId()); ownerOperator.addChild(name, dst, assosiationDst); if (log.isDebugEnabled()) { - log.debug("will attach association '" + name + "' : " + assosiationDst); + log.debug("will attach association '" + name + "' : " + + assosiationDst); } shouldUpdate = true; } Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachLink.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachLink.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/AttachLink.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -33,9 +33,8 @@ import org.nuiton.topia.persistence.util.EntityOperator; import org.nuiton.topia.persistence.util.TopiaEntityHelper; import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; -import org.nuiton.topia.replication.ReplicationEngine; import org.nuiton.topia.replication.TopiaReplicationOperation; -import org.nuiton.topia.replication.model.Link; +import org.nuiton.topia.replication.model.ReplicationLink; import org.nuiton.topia.replication.model.ReplicationModel; import org.nuiton.topia.replication.model.ReplicationNode; import org.nuiton.topia.replication.model.ReplicationOperationDef; @@ -72,13 +71,17 @@ */ public class AttachLink implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(AttachLink.class); @Override - public void register(ReplicationModel model, ReplicationNode ownerNode, ReplicationOperationPhase phase, Object... parameters) { + public void register(ReplicationModel model, + ReplicationNode ownerNode, + ReplicationOperationPhase phase, + Object... parameters) { - throw new UnsupportedOperationException(_("topia.replication.operation.error.uncreatable", getClass())); + throw new UnsupportedOperationException( + _("topia.replication.operation.error.uncreatable", getClass())); } @Override @@ -88,18 +91,20 @@ List<? extends TopiaEntity> nodeEntities, TopiaEntityIdsMap data) throws TopiaException { - Link link = (Link) operationDef.getParameters()[0]; + ReplicationLink link = (ReplicationLink) operationDef.getParameters()[0]; String name = link.getName(); if (log.isDebugEnabled()) { - log.debug("currentNode : " + operationDef.getNode() + " , link to attach : " + link); + log.debug("currentNode : " + operationDef.getNode() + + " , link to attach : " + link); } ReplicationNode ownerNode = link.getSource(); ReplicationNode cibleNode = link.getTarget(); - EntityOperator<? super TopiaEntity> ownerOperator = ownerNode.getOperator(); + EntityOperator<? super TopiaEntity> ownerOperator = + ownerNode.getOperator(); // contient la liste des ids d'association autorisees ici List<String> associationIds = null; @@ -128,7 +133,8 @@ if (ownerIds == null || ownerIds.isEmpty()) { // pas de donnees a traiter - log.info(_("topia.replication.attachAssociation.nothing.to.do", ownerOperator)); + log.info(_("topia.replication.attachAssociation.nothing.to.do", + ownerOperator)); return; } @@ -136,13 +142,17 @@ // modifiees (dettachement d'association ou autres) // ils nous faut les entites telles qu'elles sont en base source - ownerEntities = ReplicationEngine.getEntitiesList(srcCtxt, ownerIds.toArray(new String[ownerIds.size()])); + ownerEntities = TopiaEntityHelper.getEntitiesList( + srcCtxt, + ownerIds.toArray(new String[ownerIds.size()]) + ); boolean shouldCommit = false; if (log.isInfoEnabled()) { - log.info("ownerNode : " + ownerNode + " , targetNode : " + cibleNode + ", association : " + name); + log.info("ownerNode : " + ownerNode + " , targetNode : " + + cibleNode + ", association : " + name); } if (log.isDebugEnabled()) { log.debug("owner ids : " + ownerIds); @@ -152,7 +162,8 @@ for (TopiaEntity src : ownerEntities) { // les association cibles connues pour l'entite sur la base source - Collection<?> targetEntities = (Collection<?>) ownerOperator.get(name, src); + Collection<?> targetEntities = (Collection<?>) + ownerOperator.get(name, src); if (targetEntities == null || targetEntities.isEmpty()) { if (log.isDebugEnabled()) { @@ -162,7 +173,8 @@ continue; } if (log.isDebugEnabled()) { - log.debug("will try to attach " + targetEntities.size() + " association(s) '" + name + "' to " + src); + log.debug("will try to attach " + targetEntities.size() + + " association(s) '" + name + "' to " + src); } // l'entite repliquee a laquelle on veut attacher l'association @@ -170,10 +182,15 @@ TopiaEntity dst = dstCtxt.findByTopiaId(src.getTopiaId()); // les association cibles connues pour l'entite sur la base destination - Collection<?> dstTargetEntities = (Collection<?>) ownerOperator.get(name, dst); + Collection<?> dstTargetEntities = (Collection<?>) + ownerOperator.get(name, dst); // les ids des entities deja associees - List<String> dstTargetAssociationsId = dstTargetEntities == null ? Collections.EMPTY_LIST : TopiaEntityHelper.getTopiaIdList((List<? extends TopiaEntity>) dstTargetEntities); + List<String> dstTargetAssociationsId = + dstTargetEntities == null ? + Collections.<String>emptyList() : + TopiaEntityHelper.getTopiaIdList( + (List<? extends TopiaEntity>) dstTargetEntities); boolean shouldUpdate = false; for (Object a : targetEntities) { @@ -181,10 +198,12 @@ // on verifie que l'association doit etre rattachee if (associationIds.contains(assosiationSrc.getTopiaId())) { - if (dstTargetAssociationsId.contains(assosiationSrc.getTopiaId())) { + if (dstTargetAssociationsId.contains( + assosiationSrc.getTopiaId())) { // deja attache if (log.isDebugEnabled()) { - log.debug("already attached association '" + name + "' : " + assosiationSrc); + log.debug("already attached association '" + + name + "' : " + assosiationSrc); } continue; @@ -192,10 +211,12 @@ // la donnees doit etre attachee - TopiaEntity assosiationDst = dstCtxt.findByTopiaId(assosiationSrc.getTopiaId()); + TopiaEntity assosiationDst = + dstCtxt.findByTopiaId(assosiationSrc.getTopiaId()); ownerOperator.addChild(name, dst, assosiationDst); if (log.isDebugEnabled()) { - log.debug("will attach association '" + name + "' : " + assosiationDst); + log.debug("will attach association '" + name + + "' : " + assosiationDst); } shouldUpdate = true; } Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/DettachAssociation.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/DettachAssociation.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/DettachAssociation.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -54,13 +54,17 @@ */ public class DettachAssociation implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(DettachAssociation.class); @Override - public void register(ReplicationModel model, ReplicationNode ownerNode, ReplicationOperationPhase phase, Object... parameters) { + public void register(ReplicationModel model, + ReplicationNode ownerNode, + ReplicationOperationPhase phase, + Object... parameters) { - throw new UnsupportedOperationException(_("topia.replication.operation.error.uncreatable", getClass())); + throw new UnsupportedOperationException( + _("topia.replication.operation.error.uncreatable", getClass())); } @Override @@ -72,7 +76,8 @@ String name = (String) operationDef.getParameters()[0]; - EntityOperator<? super TopiaEntity> operator = operationDef.getNode().getOperator(); + EntityOperator<? super TopiaEntity> operator = + operationDef.getNode().getOperator(); // dettach les associations for (TopiaEntity e : entities) { @@ -80,7 +85,8 @@ if (size > 0) { if (log.isDebugEnabled()) { - log.debug("will dettach " + size + " association(s) '" + name + "' from " + e); + log.debug("will dettach " + size + " association(s) '" + + name + "' from " + e); } operator.setNull(name, e); } Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/Duplicate.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/Duplicate.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/Duplicate.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -52,8 +52,12 @@ public class Duplicate implements TopiaReplicationOperation { @Override - public void register(ReplicationModel model, ReplicationNode ownerNode, ReplicationOperationPhase phase, Object... parameters) { - throw new UnsupportedOperationException(_("topia.replication.operation.error.uncreatable", getClass())); + public void register(ReplicationModel model, + ReplicationNode ownerNode, + ReplicationOperationPhase phase, + Object... parameters) { + throw new UnsupportedOperationException( + _("topia.replication.operation.error.uncreatable", getClass())); } @Override Modified: trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/LoadLink.java =================================================================== --- trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/LoadLink.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/java/org/nuiton/topia/replication/operation/LoadLink.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -33,7 +33,7 @@ import org.nuiton.topia.persistence.util.EntityOperator; import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; import org.nuiton.topia.replication.TopiaReplicationOperation; -import org.nuiton.topia.replication.model.Link; +import org.nuiton.topia.replication.model.ReplicationLink; import org.nuiton.topia.replication.model.ReplicationModel; import org.nuiton.topia.replication.model.ReplicationNode; import org.nuiton.topia.replication.model.ReplicationOperationDef; @@ -55,13 +55,17 @@ */ public class LoadLink implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(LoadLink.class); @Override - public void register(ReplicationModel model, ReplicationNode ownerNode, ReplicationOperationPhase phase, Object... parameters) { + public void register(ReplicationModel model, + ReplicationNode ownerNode, + ReplicationOperationPhase phase, + Object... parameters) { - throw new UnsupportedOperationException(_("topia.replication.operation.error.uncreatable", getClass())); + throw new UnsupportedOperationException( + _("topia.replication.operation.error.uncreatable", getClass())); } @Override @@ -71,28 +75,33 @@ List<? extends TopiaEntity> nodeEntities, TopiaEntityIdsMap data) throws TopiaException { - Link link = (Link) operationDef.getParameters()[0]; + ReplicationLink link = (ReplicationLink) operationDef.getParameters()[0]; String name = link.getName(); ReplicationNode ownerNode = link.getSource(); if (!ownerNode.equals(operationDef.getNode())) { - throw new IllegalStateException(_("topia.replication.operation.loadLink.illegalSource", operationDef.getNode(), ownerNode)); + throw new IllegalStateException( + _("topia.replication.operation.loadLink.illegalSource", + operationDef.getNode(), ownerNode)); } if (log.isDebugEnabled()) { - log.debug("currentNode : " + operationDef.getNode() + " , link to load : " + link); + log.debug("currentNode : " + operationDef.getNode() + + " , link to load : " + link); } - EntityOperator<? super TopiaEntity> ownerOperator = ownerNode.getOperator(); + EntityOperator<? super TopiaEntity> ownerOperator = + ownerNode.getOperator(); for (TopiaEntity src : nodeEntities) { // on se contente de charger l'association int size = ownerOperator.sizeChild(name, src); if (log.isDebugEnabled()) { - log.debug("load association '" + name + "' on " + src + " : " + size); + log.debug("load association '" + name + "' on " + src + + " : " + size); } } } Modified: trunk/topia-service-replication/src/main/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation =================================================================== --- trunk/topia-service-replication/src/main/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/main/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,6 +1,5 @@ # -# la liste des operations disponibles pour le moteur de replication -# voir la classe org.nuiton.topia.replication.ReplicationEngine +# la liste des operations disponibles pour le moteur de replication. # org.nuiton.topia.replication.operation.AttachLink org.nuiton.topia.replication.operation.LoadLink Deleted: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractReplicationEngineTest.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractReplicationEngineTest.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractReplicationEngineTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,646 +0,0 @@ -/* - * #%L - * ToPIA :: Service Replication - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 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 - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.topia.replication; - -import org.apache.commons.logging.Log; -import org.junit.Assert; -import org.nuiton.i18n.I18n; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.framework.TopiaContextImplementor; -import org.nuiton.topia.persistence.TopiaDAO; -import org.nuiton.topia.persistence.TopiaEntity; -import org.nuiton.topia.persistence.TopiaEntityEnum; -import org.nuiton.topia.persistence.util.EntityOperator; -import org.nuiton.topia.persistence.util.EntityOperatorStore; -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.ReplicationOperationDef; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -/** - * ReplicationEngineTest. - * <p/> - * Created: 07 jun. 09 17:14:22 - * - * @author tchemit <chemit@codelutin.com> - * @version $Id$ - * @since 2.2.0 - */ -public abstract class AbstractReplicationEngineTest extends Assert { - - static protected TopiaContext context; - - static protected TopiaContext ctxt; - - protected TopiaContextImplementor dstCtxt; - - protected TopiaReplicationImplementor service; - - protected ReplicationModel model; - - static protected boolean init; - - static private Long testsTimeStamp; - - static private File testsBasedir; - - static private final String TEST_BASEDIR = "target%1$ssurefire-tests%1$s%2$td_%2$tm_%2$tY%1$s%2$tH_%2$tM_%2$tS"; - - public static void after() throws Exception { - if (context != null && !context.isClosed()) { - try { - context.closeContext(); - } catch (TopiaException e) { - // cela peut arriver si on demande la fermeture dans un thread - // ailleurs... - } - } - init = false; - } - - public void setUp() throws Exception { - - if (!init) { - - I18n.init(Locale.FRANCE); - - try { - context = createDb("source"); - } catch (Exception e) { - getLog().error("could not create db source.", e); - throw e; - } - init = true; - } - - ctxt = context.beginTransaction(); - - service = (TopiaReplicationImplementor) context.getService(TopiaReplicationService.class); - } - - public void tearDown() throws Exception { - if (ctxt != null) { - ctxt.rollbackTransaction(); - ctxt.closeContext(); - ctxt = null; - } - service = null; - } - - protected abstract TopiaContext createDb2(String name) throws Exception; - - protected abstract TopiaContext createDb(String name) throws Exception; - - protected TopiaContext createReplicateDb(Object contract) throws Exception { - TopiaContext rootCtxt = createDb2(contract.toString() + dbCounter++); - return rootCtxt; - } - - protected abstract TopiaEntityEnum[] getContracts(); - - protected abstract Log getLog(); - - protected <E extends TopiaEntity> E update(E e) throws TopiaException { - return (E) ((TopiaContextImplementor) ctxt).findByTopiaId(e.getTopiaId()); - } - - /** - * Test of detectTypes method, of class ReplicationServiceImplementor. - * - * @throws Exception if any error - */ - public void testDetectTypes() throws Exception { - } - - /** - * Test of getOperation method, of class ReplicationServiceImplementor. - * - * @throws Exception if any error - */ - public void testGetOperation() throws Exception { - } - - /** - * Test of detectAssociations method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectAssociations() throws Exception { - } - - /** - * Test of detectDirectDependencies method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectDirectDependencies() throws Exception { - } - - /** - * Test of detectShell method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectShell() throws Exception { - } - - /** - * Test of detectDependencies method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectDependencies() throws Exception { - } - - /** - * Test of detectObjectsToDettach method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectObjectsToDettach() throws Exception { - } - - /** - * Test of detectOperations method, of class ReplicationModel. - * - * @throws Exception if any error - */ - public void testDetectOperations() throws Exception { - } - - /** - * Test of doReplicate method, of class ReplicationService. - * - * @throws Exception if any error - */ - public void testDoReplicate() throws Exception { - } - - protected void detectTypes(TopiaEntity entity, Object... expectedCouple) throws TopiaException { - - Set<?> detectTypes; - - detectTypes = service.detectTypes(getContracts(), entity.getTopiaId()); - assertEquals("expected types : " + - Arrays.toString(expectedCouple) + - " but was " + detectTypes, - expectedCouple.length, detectTypes.size()); - for (Object o : expectedCouple) { - assertTrue(detectTypes.contains(o)); - } - } - - protected void getOperation(Class<? extends TopiaReplicationOperation> operationClass, boolean shouldExist) throws TopiaException { - TopiaReplicationOperation operation = service.getOperation(operationClass); - assertEquals(shouldExist, operation != null); - } - - protected void detectAssociations(TopiaEntity entity, - Object... expectedCouple) - throws TopiaException { - - createModel(entity); - model.detectAssociations(); - - assertEquals(0, expectedCouple.length % 2); - - for (int i = 0, j = expectedCouple.length / 2; i < j; i++) { - TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i]; - String name = (String) expectedCouple[2 * i + 1]; - ReplicationNode nodeSrc = model.getNode(src); - assertNotNull("association " + name + " not found", nodeSrc); - assertTrue(nodeSrc.hasAssociation()); - assertTrue(nodeSrc.getAssociations().containsKey(name)); - } - } - - protected void detectDirectDependencies(TopiaEntity entity, - Object... expectedCouple) - throws TopiaException { - - createModel(entity); - model.detectDirectDependencies(); - - assertEquals(0, expectedCouple.length % 2); - - for (int i = 0, j = expectedCouple.length / 2; i < j; i++) { - TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i]; - String name = (String) expectedCouple[2 * i + 1]; - ReplicationNode nodeSrc = model.getNode(src); - assertTrue(nodeSrc + " should have dependency but was not!", nodeSrc.hasDependency()); - assertTrue(nodeSrc + " should contain dependency " + name + "but was not! (" + nodeSrc.getDependencies() + ")", nodeSrc.getDependencies().containsKey(name)); - } - } - - protected void detectShell(TopiaEntity entity, - TopiaEntityEnum... expected) throws - TopiaException { - Set<ReplicationNode> shell; - - createModel(entity); - model.detectAssociations(); - model.detectDirectDependencies(); - model.detectShell(); - - TopiaEntityEnum c = TopiaEntityHelper.getEntityEnum( - entity.getClass(), getContracts()); - assertNotNull(c); - shell = model.getNode(c.getContract()).getShell(); - assertEquals( - "expected shell : " + Arrays.toString(expected) + ", but was " + - shell, expected.length, shell.size()); - - for (int i = 0, j = expected.length; i < j; i++) { - TopiaEntityEnum type = expected[i]; - ReplicationNode node = model.getNode(type.getContract()); - assertTrue(shell.contains(node)); - assertEquals(type, node.getContract()); - } - } - - protected void detectDependencies( - TopiaEntity entity, - TopiaEntityEnum[]... expected) throws TopiaException { - - createModel(entity); - model.detectAssociations(); - model.detectDirectDependencies(); - model.detectShell(); - model.detectDependencies(); - List<ReplicationNode> dependencies = model.getOrder(); - - int i = 0; - for (ReplicationNode level : dependencies) { - getLog().info("level " + level + " = " + level); - } - -// assertEquals("expected " + expected.length + " levels but had " + dependencies.size(), expected.length, dependencies.size()); -// -// Iterator<List<ReplicationNode>> order = dependencies.iterator(); -// if (entity != null) { -// getLog().info("for " + entity.getTopiaId()); -// } -// int index = 0; -// for (TopiaEntityEnum[] expectedLevel : expected) { -// -// List<ReplicationNode> next = order.next(); -// getLog().info("level " + (index++) + " : " + next); -// for (TopiaEntityEnum ee : expectedLevel) { -// ReplicationNode expectedNode = model.getNode(ee); -// -// assertTrue("should have contains node " + expectedNode, next.contains(expectedNode)); -// } -// -// } - } - - protected void detectObjectsToDettach(TopiaEntity entity, Object... expected) throws TopiaException { - - assertEquals(0, expected.length % 2); - - createModel(entity); - model.detectAssociations(); - model.detectDirectDependencies(); - model.detectShell(); - model.detectDependencies(); - model.detectObjectsToDettach(); - Set<ReplicationNode> nodes = new HashSet<ReplicationNode>(); - - for (int i = 0, j = expected.length / 2; i < j; i++) { - TopiaEntityEnum e = (TopiaEntityEnum) expected[2 * i]; - ReplicationNode node = model.getNode(e); - String[] ids = (String[]) expected[2 * i + 1]; - assertEquals(ids.length > 0, node.hasAssociationsToDettach()); - for (String id : ids) { - assertTrue(node.getAssociationsToDettach().contains(id)); - } - nodes.add(node); - } - - for (ReplicationNode node : model.getNodes()) { - if (!nodes.contains(node)) { - // on verifie bien qu'il n' y a pas d'associations dettachee - assertFalse(node.hasAssociationsToDettach()); - } - } - - } - - protected void detectOperations(TopiaEntity entity, Object... expected) throws TopiaException { - - assertEquals(0, expected.length % 2); - - if (entity == null) { - prepareModel(); - } else { - prepareModel(entity.getTopiaId()); - } -// createModel(entity); -// model.detectAssociations(); -// model.detectDirectDependencies(); -// model.detectShell(); -// model.detectDependencies(); -// model.detectObjectsToDettach(); -// model.detectOperations(); - - if (getLog().isInfoEnabled()) { - getLog().info("=========================================================================="); - if (entity == null) { - - getLog().info("resume of operations for all "); - } else { - getLog().info("resume of operations for entity " + entity.getTopiaId()); - } - - for (ReplicationNode node : model.getOrder()) { - List<ReplicationOperationDef> operations = node.getOperations(); - for (ReplicationOperationDef op : operations) { - getLog().info("[" + node + "] : operation " + op); - } - } - getLog().info("=========================================================================="); - } - } - - private static int dbCounter; - - protected void doReplicate(TopiaEntityEnum contract, TopiaEntity... entity) throws Exception { - - TopiaContext rootCtxt = createReplicateDb("doReplicate_" + contract); - - List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity)); - getLog().info("entity " + ids); - - prepareModel(ids.toArray(new String[ids.size()])); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - - service.doReplicate(model, dstCtxt); - - //dstCtxt.closeContext(); - - if (entity.length == 0) { - - return; - } - dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); - - for (TopiaEntity e : entity) { - TopiaEntity actual = dstCtxt.findByTopiaId(e.getTopiaId()); - assertNotNull(actual); - assertEquals(e, actual); - } - - dstCtxt.closeContext(); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - } - - protected void doReplicateAll() throws Exception { - - TopiaContext rootCtxt = createReplicateDb("doReplicateAll"); - - prepareModelAll(); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - - service.doReplicate(model, dstCtxt); - - TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt; - dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); - - assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2); - - dstCtxt.closeContext(); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - } - - protected void doReplicateWithComputedOrder(TopiaEntity... entity) throws Exception { - - TopiaContext rootCtxt = createReplicateDb("doReplicateWithComputedOrder"); - - List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity)); - - prepareModelWithComputedOrder(ids.toArray(new String[ids.size()])); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - - service.doReplicate(model, dstCtxt); - - getLog().info("replication is done for " + Arrays.toString(entity) + ", will verify data..."); - - TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt; - dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); - - assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2); - - dstCtxt.closeContext(); - - dstCtxt = (TopiaContextImplementor) rootCtxt; - } - - protected void assertDbEquals(TopiaEntityEnum[] contracts, TopiaContextImplementor ctxt, TopiaContextImplementor ctxt2) throws TopiaException { - Set<String> ids = new HashSet<String>(); - - if (getLog().isInfoEnabled()) { - getLog().info("will verify db for contracts " + Arrays.toString(contracts)); - } - for (TopiaEntityEnum c : contracts) { - if (getLog().isDebugEnabled()) { - getLog().debug("verify for contract " + c); - } - TopiaDAO<? extends TopiaEntity> daoSrc = ctxt.getDAO(c.getContract()); - TopiaDAO<? extends TopiaEntity> daoDst = ctxt2.getDAO(c.getContract()); - long nbSrc = daoSrc.count(); - long nbDst = daoDst.count(); - assertEquals("le nombres d'entites de type " + c + " devrait etre " + nbSrc + " mais est " + nbDst, nbSrc, nbDst); - List<String> idsSrc = daoSrc.findAllIds(); - List<String> idsDst = daoDst.findAllIds(); - Collections.sort(idsSrc); - Collections.sort(idsDst); - assertEquals(idsSrc, idsDst); - for (String id : idsSrc) { - if (getLog().isDebugEnabled()) { - getLog().debug("verify for entity " + id); - } - TopiaEntity eSrc = daoSrc.findByTopiaId(id); - TopiaEntity eDst = daoDst.findByTopiaId(id); - assertEquals(eSrc, eDst); - assertEntityEquals(eSrc, eDst, ids); - } - } - } - - protected void assertEntityEquals(TopiaEntity expected, TopiaEntity actual, Set<String> treated) { - if (treated == null) { - treated = new HashSet<String>(); - } - if (treated.contains(actual.getTopiaId())) { - return; - } - if (getLog().isDebugEnabled()) { - getLog().debug(expected); - } - assertEquals(actual.getTopiaId(), expected.getTopiaId()); - treated.add(actual.getTopiaId()); - if (getLog().isDebugEnabled()) { - getLog().debug("expected : " + expected + " / actual " + actual); - } - TopiaEntityEnum contract = TopiaEntityHelper.getEntityEnum(expected.getClass(), getContracts()); - if (contract == null) { - // this type of entity in not dealed here... - getLog().debug("untested property type " + expected.getClass()); - return; - } - Assert.assertNotNull( - "contract not found for " + expected.getClass() + " in " + - Arrays.toString(getContracts()), contract); - EntityOperator<TopiaEntity> operator = EntityOperatorStore.getOperator(contract); - List<String> associationProperties = operator.getAssociationProperties(); - for (String name : associationProperties) { - if (getLog().isDebugEnabled()) { - getLog().debug("association " + name); - } - if (operator.isChildEmpty(name, expected)) { - assertTrue("l'association " + name + " devrait etre vide mais possede " + operator.sizeChild(name, actual) + " entrees", operator.isChildEmpty(name, actual)); - } else { - assertFalse("l'association " + name + " devrait posseder " + operator.isChildEmpty(name, expected) + " mais est vide", operator.isChildEmpty(name, actual)); - - } - assertEquals(operator.isChildEmpty(name, actual), operator.isChildEmpty(name, expected)); - - Class<?> type = operator.getAssociationPropertyType(name); - Collection<?> src = (Collection<?>) operator.get(name, expected); - Collection<?> dst = (Collection<?>) operator.get(name, actual); -// assertEquals(src, dst); - Iterator<?> itrSrc = src.iterator(); - Iterator<?> itrDst = dst.iterator(); - while (itrSrc.hasNext()) { - if (TopiaEntity.class.isAssignableFrom(type)) { - assertEntityEquals((TopiaEntity) itrSrc.next(), (TopiaEntity) itrDst.next(), treated); - } else { - assertEquals(itrSrc.next(), itrDst.next()); - } - } - } - - for (String name : operator.getProperties()) { - if (getLog().isDebugEnabled()) { - getLog().debug("dependency " + name); - } - if (associationProperties.contains(name)) { - // deja traite au dessus - continue; - } - Class<?> type = operator.getPropertyType(name); - Object src = operator.get(name, expected); - Object dst = operator.get(name, actual); - assertFalse(src == null && dst != null); - assertFalse(src != null && dst == null); - if (src == null) { - continue; - } - if (TopiaEntity.class.isAssignableFrom(type)) { - assertEntityEquals((TopiaEntity) src, (TopiaEntity) dst, treated); - } else { - assertEquals(src, dst); - } - } - } - - protected void createUnsupportedBeforeOperation(TopiaEntityEnum contract, TopiaEntity entity, Class<? extends TopiaReplicationOperation> operationClass, Object... parameters) throws Exception { - - getLog().info("entity " + entity.getTopiaId()); - prepareModel(entity.getTopiaId()); - - service.addBeforeOperation(model, contract, operationClass, parameters); - // on ne doit pas avoir le droit de creer cette operation - fail(); - } - - protected void createUnsupportedAfterOperation(TopiaEntityEnum contract, TopiaEntity entity, Class<? extends TopiaReplicationOperation> operationClass, Object... parameters) throws Exception { - - getLog().info("entity " + entity.getTopiaId()); - prepareModel(entity.getTopiaId()); -// model = service.createModel(getContracts()); -// model.detectDirectDependencies(); - service.addAfterOperation(model, contract, operationClass, parameters); - // on ne doit pas avoir le droit de creer cette operation - fail(); - } - - protected Long getTestsTimeStamp() { - if (testsTimeStamp == null) { - testsTimeStamp = System.currentTimeMillis(); - getLog().info("tests timestamp : " + testsTimeStamp); - } - return testsTimeStamp; - } - - protected File getTestDir(Class<?> testClass) { - if (testsBasedir == null) { - String tmp = System.getProperty("basedir"); - if (tmp == null) { - tmp = new File("").getAbsolutePath(); - } - String name = String.format(TEST_BASEDIR, File.separator, new Date(getTestsTimeStamp())); - testsBasedir = new File(new File(tmp), name); - getLog().info("tests basedir : " + testsBasedir); - } - return new File(testsBasedir, testClass.getSimpleName()); - } - - protected void createModel(TopiaEntity entity) throws TopiaException { - model = service.createModel(getContracts(), entity.getTopiaId()); - } - - protected void prepareModel(String... ids) throws TopiaException { - model = service.prepare(getContracts(), ids); - } - - protected void prepareModelAll() throws TopiaException { - model = service.prepareForAll(getContracts()); - } - - protected void prepareModelWithComputedOrder(String... ids) throws TopiaException { - model = service.prepareWithComputedOrder(getContracts(), ids); - } -} - - Copied: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractTopiaReplicationServiceTest.java (from rev 2098, trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractReplicationEngineTest.java) =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractTopiaReplicationServiceTest.java (rev 0) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractTopiaReplicationServiceTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,654 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.junit.Assert; +import org.nuiton.i18n.I18n; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.framework.TopiaContextImplementor; +import org.nuiton.topia.persistence.TopiaDAO; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaEntityEnum; +import org.nuiton.topia.persistence.util.EntityOperator; +import org.nuiton.topia.persistence.util.EntityOperatorStore; +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.ReplicationOperationDef; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * TopiaReplicationServiceImplTest. + * <p/> + * Created: 07 jun. 09 17:14:22 + * + * @author tchemit <chemit@codelutin.com> + * @version $Id$ + * @since 2.2.0 + */ +public abstract class AbstractTopiaReplicationServiceTest extends Assert { + + static protected TopiaContext context; + + static protected TopiaContext ctxt; + + protected TopiaContextImplementor dstCtxt; + + protected TopiaReplicationService service; + + protected ReplicationModel model; + + static protected boolean init; + + static private Long testsTimeStamp; + + static private File testsBasedir; + + static private final String TEST_BASEDIR = "target%1$ssurefire-tests%1$s%2$td_%2$tm_%2$tY%1$s%2$tH_%2$tM_%2$tS"; + + public static void after() throws Exception { + if (context != null && !context.isClosed()) { + try { + context.closeContext(); + } catch (TopiaException e) { + // cela peut arriver si on demande la fermeture dans un thread + // ailleurs... + } + } + init = false; + } + + public void setUp() throws Exception { + + if (!init) { + + I18n.init(Locale.FRANCE); + + try { + context = createDb("source"); + } catch (Exception e) { + getLog().error("could not create db source.", e); + throw e; + } + init = true; + } + + ctxt = context.beginTransaction(); + + service = context.getService(TopiaReplicationService.class); + } + + public void tearDown() throws Exception { + if (ctxt != null) { + ctxt.rollbackTransaction(); + ctxt.closeContext(); + ctxt = null; + } + service = null; + } + + protected abstract TopiaContext createDb2(String name) throws Exception; + + protected abstract TopiaContext createDb(String name) throws Exception; + + protected TopiaContext createReplicateDb(Object contract) throws Exception { + TopiaContext rootCtxt = createDb2(contract.toString() + dbCounter++); + return rootCtxt; + } + + protected abstract TopiaEntityEnum[] getContracts(); + + protected abstract Log getLog(); + + protected <E extends TopiaEntity> E update(E e) throws TopiaException { + return (E) ((TopiaContextImplementor) ctxt).findByTopiaId(e.getTopiaId()); + } + + /** + * Test of detectTypes method, of class ReplicationServiceImplementor. + * + * @throws Exception if any error + */ + public void testDetectTypes() throws Exception { + } + + /** + * Test of getOperation method, of class ReplicationServiceImplementor. + * + * @throws Exception if any error + */ + public void testGetOperation() throws Exception { + } + + /** + * Test of detectAssociations method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectAssociations() throws Exception { + } + + /** + * Test of detectDirectDependencies method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectDirectDependencies() throws Exception { + } + + /** + * Test of detectShell method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectShell() throws Exception { + } + + /** + * Test of detectDependencies method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectDependencies() throws Exception { + } + + /** + * Test of detectObjectsToDettach method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectObjectsToDettach() throws Exception { + } + + /** + * Test of detectOperations method, of class ReplicationModel. + * + * @throws Exception if any error + */ + public void testDetectOperations() throws Exception { + } + + /** + * Test of doReplicate method, of class ReplicationService. + * + * @throws Exception if any error + */ + public void testDoReplicate() throws Exception { + } + + protected void detectTypes(TopiaEntity entity, Object... expectedCouple) throws TopiaException { + + Set<?> detectTypes; + + detectTypes = service.getModelBuilder().detectTypes(context, getContracts(), entity.getTopiaId()); + assertEquals("expected types : " + + Arrays.toString(expectedCouple) + + " but was " + detectTypes, + expectedCouple.length, detectTypes.size()); + for (Object o : expectedCouple) { + assertTrue(detectTypes.contains(o)); + } + } + + protected void getOperation(Class<? extends TopiaReplicationOperation> operationClass, boolean shouldExist) throws TopiaException { + TopiaReplicationOperation operation = service.getModelBuilder().getOperation(operationClass); + assertEquals(shouldExist, operation != null); + } + + protected void detectAssociations(TopiaEntity entity, + Object... expectedCouple) + throws TopiaException { + + createModel(entity); + model.detectAssociations(); + + assertEquals(0, expectedCouple.length % 2); + + for (int i = 0, j = expectedCouple.length / 2; i < j; i++) { + TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i]; + String name = (String) expectedCouple[2 * i + 1]; + ReplicationNode nodeSrc = model.getNode(src); + assertNotNull("association " + name + " not found", nodeSrc); + assertTrue(nodeSrc.hasAssociation()); + assertTrue(nodeSrc.getAssociations().containsKey(name)); + } + } + + protected void detectDirectDependencies(TopiaEntity entity, + Object... expectedCouple) + throws TopiaException { + + createModel(entity); + model.detectDirectDependencies(); + + assertEquals(0, expectedCouple.length % 2); + + for (int i = 0, j = expectedCouple.length / 2; i < j; i++) { + TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i]; + String name = (String) expectedCouple[2 * i + 1]; + ReplicationNode nodeSrc = model.getNode(src); + assertTrue(nodeSrc + " should have dependency but was not!", nodeSrc.hasDependency()); + assertTrue(nodeSrc + " should contain dependency " + name + "but was not! (" + nodeSrc.getDependencies() + ")", nodeSrc.getDependencies().containsKey(name)); + } + } + + protected void detectShell(TopiaEntity entity, + TopiaEntityEnum... expected) throws + TopiaException { + Set<ReplicationNode> shell; + + createModel(entity); + model.detectAssociations(); + model.detectDirectDependencies(); + model.detectShell(); + + TopiaEntityEnum c = TopiaEntityHelper.getEntityEnum( + entity.getClass(), getContracts()); + assertNotNull(c); + shell = model.getNode(c.getContract()).getShell(); + assertEquals( + "expected shell : " + Arrays.toString(expected) + ", but was " + + shell, expected.length, shell.size()); + + for (int i = 0, j = expected.length; i < j; i++) { + TopiaEntityEnum type = expected[i]; + ReplicationNode node = model.getNode(type.getContract()); + assertTrue(shell.contains(node)); + assertEquals(type, node.getContract()); + } + } + + protected void detectDependencies( + TopiaEntity entity, + TopiaEntityEnum[]... expected) throws TopiaException { + + createModel(entity); + model.detectAssociations(); + model.detectDirectDependencies(); + model.detectShell(); + model.detectDependencies(); + List<ReplicationNode> dependencies = model.getOrder(); + + int i = 0; + for (ReplicationNode level : dependencies) { + getLog().info("level " + level + " = " + level); + } + +// assertEquals("expected " + expected.length + " levels but had " + dependencies.size(), expected.length, dependencies.size()); +// +// Iterator<List<ReplicationNode>> order = dependencies.iterator(); +// if (entity != null) { +// getLog().info("for " + entity.getTopiaId()); +// } +// int index = 0; +// for (TopiaEntityEnum[] expectedLevel : expected) { +// +// List<ReplicationNode> next = order.next(); +// getLog().info("level " + (index++) + " : " + next); +// for (TopiaEntityEnum ee : expectedLevel) { +// ReplicationNode expectedNode = model.getNode(ee); +// +// assertTrue("should have contains node " + expectedNode, next.contains(expectedNode)); +// } +// +// } + } + + protected void detectObjectsToDettach(TopiaEntity entity, Object... expected) throws TopiaException { + + assertEquals(0, expected.length % 2); + + createModel(entity); + model.detectAssociations(); + model.detectDirectDependencies(); + model.detectShell(); + model.detectDependencies(); + model.detectObjectsToDettach(); + Set<ReplicationNode> nodes = new HashSet<ReplicationNode>(); + + for (int i = 0, j = expected.length / 2; i < j; i++) { + TopiaEntityEnum e = (TopiaEntityEnum) expected[2 * i]; + ReplicationNode node = model.getNode(e); + String[] ids = (String[]) expected[2 * i + 1]; + assertEquals(ids.length > 0, node.hasAssociationsToDettach()); + for (String id : ids) { + assertTrue(node.getAssociationsToDettach().contains(id)); + } + nodes.add(node); + } + + for (ReplicationNode node : model.getNodes()) { + if (!nodes.contains(node)) { + // on verifie bien qu'il n' y a pas d'associations dettachee + assertFalse(node.hasAssociationsToDettach()); + } + } + + } + + protected void detectOperations(TopiaEntity entity, Object... expected) throws TopiaException { + + assertEquals(0, expected.length % 2); + + if (entity == null) { + prepareModel(); + } else { + prepareModel(entity.getTopiaId()); + } +// createModel(entity); +// model.detectAssociations(); +// model.detectDirectDependencies(); +// model.detectShell(); +// model.detectDependencies(); +// model.detectObjectsToDettach(); +// model.detectOperations(); + + if (getLog().isInfoEnabled()) { + getLog().info("=========================================================================="); + if (entity == null) { + + getLog().info("resume of operations for all "); + } else { + getLog().info("resume of operations for entity " + entity.getTopiaId()); + } + + for (ReplicationNode node : model.getOrder()) { + List<ReplicationOperationDef> operations = node.getOperations(); + for (ReplicationOperationDef op : operations) { + getLog().info("[" + node + "] : operation " + op); + } + } + getLog().info("=========================================================================="); + } + } + + private static int dbCounter; + + protected void doReplicate(TopiaEntityEnum contract, TopiaEntity... entity) throws Exception { + + TopiaContext rootCtxt = createReplicateDb("doReplicate_" + contract); + + List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity)); + getLog().info("entity " + ids); + + prepareModel(ids.toArray(new String[ids.size()])); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + + service.doReplicate(model, dstCtxt); + + //dstCtxt.closeContext(); + + if (entity.length == 0) { + + return; + } + dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); + + for (TopiaEntity e : entity) { + TopiaEntity actual = dstCtxt.findByTopiaId(e.getTopiaId()); + assertNotNull(actual); + assertEquals(e, actual); + } + + dstCtxt.closeContext(); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + } + + protected void doReplicateAll() throws Exception { + + TopiaContext rootCtxt = createReplicateDb("doReplicateAll"); + + prepareModelAll(); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + + service.doReplicate(model, dstCtxt); + + TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt; + dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); + + assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2); + + dstCtxt.closeContext(); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + } + + protected void doReplicateWithComputedOrder(TopiaEntity... entity) throws Exception { + + TopiaContext rootCtxt = createReplicateDb("doReplicateWithComputedOrder"); + + List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity)); + + prepareModelWithComputedOrder(ids.toArray(new String[ids.size()])); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + + service.doReplicate(model, dstCtxt); + + getLog().info("replication is done for " + Arrays.toString(entity) + ", will verify data..."); + + TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt; + dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction(); + + assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2); + + dstCtxt.closeContext(); + + dstCtxt = (TopiaContextImplementor) rootCtxt; + } + + protected void assertDbEquals(TopiaEntityEnum[] contracts, + TopiaContextImplementor ctxt, + TopiaContextImplementor ctxt2) throws TopiaException { + Set<String> ids = new HashSet<String>(); + + if (getLog().isInfoEnabled()) { + getLog().info("will verify db for contracts " + Arrays.toString(contracts)); + } + for (TopiaEntityEnum c : contracts) { + if (getLog().isDebugEnabled()) { + getLog().debug("verify for contract " + c); + } + TopiaDAO<? extends TopiaEntity> daoSrc = ctxt.getDAO(c.getContract()); + TopiaDAO<? extends TopiaEntity> daoDst = ctxt2.getDAO(c.getContract()); + long nbSrc = daoSrc.count(); + long nbDst = daoDst.count(); + assertEquals("le nombres d'entites de type " + c + " devrait etre " + nbSrc + " mais est " + nbDst, nbSrc, nbDst); + List<String> idsSrc = daoSrc.findAllIds(); + List<String> idsDst = daoDst.findAllIds(); + Collections.sort(idsSrc); + Collections.sort(idsDst); + assertEquals(idsSrc, idsDst); + for (String id : idsSrc) { + if (getLog().isDebugEnabled()) { + getLog().debug("verify for entity " + id); + } + TopiaEntity eSrc = daoSrc.findByTopiaId(id); + TopiaEntity eDst = daoDst.findByTopiaId(id); + assertEquals(eSrc, eDst); + assertEntityEquals(eSrc, eDst, ids); + } + } + } + + protected void assertEntityEquals(TopiaEntity expected, + TopiaEntity actual, + Set<String> treated) { + if (treated == null) { + treated = new HashSet<String>(); + } + if (treated.contains(actual.getTopiaId())) { + return; + } + if (getLog().isDebugEnabled()) { + getLog().debug(expected); + } + assertEquals(actual.getTopiaId(), expected.getTopiaId()); + treated.add(actual.getTopiaId()); + if (getLog().isDebugEnabled()) { + getLog().debug("expected : " + expected + " / actual " + actual); + } + TopiaEntityEnum contract = TopiaEntityHelper.getEntityEnum(expected.getClass(), getContracts()); + if (contract == null) { + // this type of entity in not dealed here... + getLog().debug("untested property type " + expected.getClass()); + return; + } + Assert.assertNotNull( + "contract not found for " + expected.getClass() + " in " + + Arrays.toString(getContracts()), contract); + EntityOperator<TopiaEntity> operator = EntityOperatorStore.getOperator(contract); + List<String> associationProperties = operator.getAssociationProperties(); + for (String name : associationProperties) { + if (getLog().isDebugEnabled()) { + getLog().debug("association " + name); + } + if (operator.isChildEmpty(name, expected)) { + assertTrue("l'association " + name + " devrait etre vide mais possede " + operator.sizeChild(name, actual) + " entrees", operator.isChildEmpty(name, actual)); + } else { + assertFalse("l'association " + name + " devrait posseder " + operator.isChildEmpty(name, expected) + " mais est vide", operator.isChildEmpty(name, actual)); + + } + assertEquals(operator.isChildEmpty(name, actual), operator.isChildEmpty(name, expected)); + + Class<?> type = operator.getAssociationPropertyType(name); + Collection<?> src = (Collection<?>) operator.get(name, expected); + Collection<?> dst = (Collection<?>) operator.get(name, actual); +// assertEquals(src, dst); + Iterator<?> itrSrc = src.iterator(); + Iterator<?> itrDst = dst.iterator(); + while (itrSrc.hasNext()) { + if (TopiaEntity.class.isAssignableFrom(type)) { + assertEntityEquals((TopiaEntity) itrSrc.next(), (TopiaEntity) itrDst.next(), treated); + } else { + assertEquals(itrSrc.next(), itrDst.next()); + } + } + } + + for (String name : operator.getProperties()) { + if (getLog().isDebugEnabled()) { + getLog().debug("dependency " + name); + } + if (associationProperties.contains(name)) { + // deja traite au dessus + continue; + } + Class<?> type = operator.getPropertyType(name); + Object src = operator.get(name, expected); + Object dst = operator.get(name, actual); + assertFalse(src == null && dst != null); + assertFalse(src != null && dst == null); + if (src == null) { + continue; + } + if (TopiaEntity.class.isAssignableFrom(type)) { + assertEntityEquals((TopiaEntity) src, (TopiaEntity) dst, treated); + } else { + assertEquals(src, dst); + } + } + } + + protected void createUnsupportedBeforeOperation(TopiaEntityEnum contract, + TopiaEntity entity, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) throws Exception { + + getLog().info("entity " + entity.getTopiaId()); + prepareModel(entity.getTopiaId()); + + service.addBeforeOperation(model, contract, operationClass, parameters); + // on ne doit pas avoir le droit de creer cette operation + fail(); + } + + protected void createUnsupportedAfterOperation(TopiaEntityEnum contract, + TopiaEntity entity, + Class<? extends TopiaReplicationOperation> operationClass, + Object... parameters) throws Exception { + + getLog().info("entity " + entity.getTopiaId()); + prepareModel(entity.getTopiaId()); +// model = service.createModel(getContracts()); +// model.detectDirectDependencies(); + service.addAfterOperation(model, contract, operationClass, parameters); + // on ne doit pas avoir le droit de creer cette operation + fail(); + } + + protected Long getTestsTimeStamp() { + if (testsTimeStamp == null) { + testsTimeStamp = System.currentTimeMillis(); + getLog().info("tests timestamp : " + testsTimeStamp); + } + return testsTimeStamp; + } + + protected File getTestDir(Class<?> testClass) { + if (testsBasedir == null) { + String tmp = System.getProperty("basedir"); + if (tmp == null) { + tmp = new File("").getAbsolutePath(); + } + String name = String.format(TEST_BASEDIR, File.separator, new Date(getTestsTimeStamp())); + testsBasedir = new File(new File(tmp), name); + getLog().info("tests basedir : " + testsBasedir); + } + return new File(testsBasedir, testClass.getSimpleName()); + } + + protected void createModel(TopiaEntity entity) throws TopiaException { + model = service.getModelBuilder().createModel(context, getContracts(), entity.getTopiaId()); + } + + protected void prepareModel(String... ids) throws TopiaException { + model = service.prepare(getContracts(), ids); + } + + protected void prepareModelAll() throws TopiaException { + model = service.prepareForAll(getContracts()); + } + + protected void prepareModelWithComputedOrder(String... ids) throws TopiaException { + model = service.prepareWithComputedOrder(getContracts(), ids); + } +} Property changes on: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/AbstractTopiaReplicationServiceTest.java ___________________________________________________________________ Added: svn:keywords + HeadURL Id Date Revision Author Deleted: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineAllTest.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineAllTest.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineAllTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,296 +0,0 @@ -/* - * #%L - * ToPIA :: Service Replication - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 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 - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.topia.replication; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaContextFactory; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.TopiaTestDAOHelper.TopiaTestEntityEnum; -import org.nuiton.topia.framework.TopiaContextImplementor; -import org.nuiton.topia.persistence.TopiaEntity; -import org.nuiton.topia.persistence.TopiaEntityEnum; -import org.nuiton.topia.test.entities.Person; -import org.nuiton.topia.test.entities.PersonImpl; -import org.nuiton.topia.test.entities.Pet; -import org.nuiton.topia.test.entities.PetImpl; -import org.nuiton.topia.test.entities.Race; -import org.nuiton.topia.test.entities.RaceImpl; - -import java.io.File; -import java.util.Properties; - -/** - * ReplicationEngineTest on model TopiaTest - * <p/> - * Created: 07 jun. 09 17:14:22 - * - * @author tchemit <chemit@codelutin.com> - * @since 2.2.0 - */ -public class ReplicationEngineAllTest extends AbstractReplicationEngineTest { - - /** to use log facility, just put in your code: log.info(\"...\"); */ - private static final Log log = LogFactory.getLog(ReplicationEngineTest.class); - - protected static final TopiaEntityEnum[] contracts = { - TopiaTestEntityEnum.Person, - TopiaTestEntityEnum.Pet, - TopiaTestEntityEnum.Race - }; - - protected static final String entitiesList = - PersonImpl.class.getName() + "," + - PetImpl.class.getName() + "," + - RaceImpl.class.getName(); - - static protected Person person, person2; - - static protected Pet pet, pet2, pet3; - - static protected Race race, race2, race3; - - @AfterClass - public static void after() throws Exception { - AbstractReplicationEngineTest.after(); - } - - @Before - @Override - public void setUp() throws Exception { - - super.setUp(); - - person = update(person); - person2 = update(person2); - pet = update(pet); - pet2 = update(pet2); - race = update(race); - race2 = update(race2); - race3 = update(race3); - } - - @After - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (dstCtxt != null && !dstCtxt.isClosed()) { - dstCtxt.closeContext(); - } - } - -// @Ignore - - @Test - @Override - public void testDetectTypes() throws Exception { - - detectTypes(race, Race.class); - detectTypes(pet, Pet.class, Person.class, Race.class); - detectTypes(person, Pet.class, Person.class, Race.class); - - detectTypes(pet2, Pet.class); - detectTypes(person2, Person.class); - detectTypes(race2, Race.class); - - detectTypes(race3, Race.class); - detectTypes(pet3, Pet.class, Race.class); - } - -// @Ignore - - @Test - @Override - public void testGetOperation() throws Exception { - } - -// @Ignore - - @Test - @Override - public void testDetectAssociations() throws Exception { - - detectAssociations(person, TopiaTestEntityEnum.Person, Person.PROPERTY_PET); - detectAssociations(race); - detectAssociations(pet); - - detectAssociations(person2); - detectAssociations(race2); - detectAssociations(pet2); - - } - -// @Ignore - - @Test - @Override - public void testDetectDirectDependencies() throws Exception { - - detectDirectDependencies(person); - detectDirectDependencies(race); - detectDirectDependencies(pet, TopiaTestEntityEnum.Pet, Pet.PROPERTY_PERSON, TopiaTestEntityEnum.Pet, Pet.PROPERTY_RACE); - - detectDirectDependencies(person2); - detectDirectDependencies(race2); - detectDirectDependencies(pet2); - } - -// @Ignore - - @Test - @Override - public void testDetectShell() throws Exception { - - detectShell(person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); - detectShell(race); - detectShell(pet, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); - detectShell(person2, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); - detectShell(race2); - detectShell(pet2, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); - } - -// @Ignore - - @Test - @Override - public void testDetectDependencies() throws Exception { - - detectDependencies(null, - new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); - } - -// @Ignore - - @Test - @Override - public void testDetectObjectsToDettach() throws Exception { - - detectObjectsToDettach(null, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); - } - -// @Ignore - - @Test - @Override - public void testDetectOperations() throws Exception { - - detectOperations(null); - } - -// @Ignore - - @Test - @Override - public void testDoReplicate() throws Exception { - - doReplicateAll(); - - } - - @Override - protected TopiaContext createDb(String name) throws Exception { - - File localDB = new File(getTestDir(getClass()), "db_" + name); - - Properties config = getH2Properties(localDB); - - context = TopiaContextFactory.getContext(config); - - TopiaContextImplementor tx = (TopiaContextImplementor) context.beginTransaction(); - - person = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding master"); - race = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race I"); - pet = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding", Pet.PROPERTY_PERSON, person, Pet.PROPERTY_RACE, race); - - person2 = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding II master"); - pet2 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding II"); - race2 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race II"); - - race3 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race III"); - pet3 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding III", Pet.PROPERTY_RACE, race3); - - tx.commitTransaction(); - tx.closeContext(); - return context; - } - - @Override - protected TopiaContext createDb2(String name) throws Exception { - - File localDB = new File(getTestDir(getClass()), "db_" + name); - - Properties config = getH2Properties(localDB); - - return TopiaContextFactory.getContext(config); - } - - @Override - protected TopiaEntityEnum[] getContracts() { - return contracts; - } - - @Override - protected Log getLog() { - return log; - } - - protected Properties getH2Properties(File f) { - - Properties config = new Properties(); - config.setProperty("hibernate.show_sql", "false"); - config.setProperty("hibernate.hbm2ddl.auto", "create"); - - config.setProperty("topia.persistence.classes", entitiesList); - config.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); - config.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); - config.setProperty("hibernate.connection.url", "jdbc:h2:file:" + f.getAbsolutePath() + ";create=true"); - config.setProperty("hibernate.connection.username", "sa"); - config.setProperty("hibernate.connection.password", ""); - - config.setProperty("topia.service.replication", ReplicationEngine.class.getName()); - - return config; - } - - - @Override - protected void createModel(TopiaEntity entity) throws TopiaException { - model = service.createModelForAll(getContracts()); - } - - @Override - protected void prepareModel(String... ids) throws TopiaException { - model = service.prepareForAll(getContracts()); - } - -} - - Deleted: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineTest.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineTest.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,445 +0,0 @@ -/* - * #%L - * ToPIA :: Service Replication - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 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 - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ - -package org.nuiton.topia.replication; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaContextFactory; -import org.nuiton.topia.TopiaException; -import org.nuiton.topia.TopiaTestDAOHelper.TopiaTestEntityEnum; -import org.nuiton.topia.framework.TopiaContextImplementor; -import org.nuiton.topia.persistence.TopiaEntityEnum; -import org.nuiton.topia.replication.model.ReplicationModel; -import org.nuiton.topia.replication.operation.AttachAssociation; -import org.nuiton.topia.replication.operation.DettachAssociation; -import org.nuiton.topia.replication.operation.Duplicate; -import org.nuiton.topia.replication.operation.FakeOperation; -import org.nuiton.topia.replication.operation.UncreatableOperation; -import org.nuiton.topia.replication.operation.UnregistredOperation; -import org.nuiton.topia.test.entities.Person; -import org.nuiton.topia.test.entities.PersonImpl; -import org.nuiton.topia.test.entities.Pet; -import org.nuiton.topia.test.entities.PetImpl; -import org.nuiton.topia.test.entities.Race; -import org.nuiton.topia.test.entities.RaceImpl; - -import java.io.File; -import java.util.Properties; - -/** - * ReplicationEngineTest on model TopiaTest - * <p/> - * Created: 07 jun. 09 17:14:22 - * - * @author tchemit <chemit@codelutin.com> - * @since 2.2.0 - */ -public class ReplicationEngineTest extends AbstractReplicationEngineTest { - - /** to use log facility, just put in your code: log.info(\"...\"); */ - private static final Log log = LogFactory.getLog(ReplicationEngineTest.class); - - protected static final TopiaEntityEnum[] contracts = {TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race}; - - protected static final String entitiesList = PersonImpl.class.getName() + "," + PetImpl.class.getName() + "," + RaceImpl.class.getName(); - - static protected Person person, person2; - - static protected Pet pet, pet2, pet3; - - static protected Race race, race2, race3; - - @AfterClass - public static void after() throws Exception { - AbstractReplicationEngineTest.after(); - } - - @Before - @Override - public void setUp() throws Exception { - - super.setUp(); - - person = update(person); - person2 = update(person2); - pet = update(pet); - pet2 = update(pet2); - race = update(race); - race2 = update(race2); - race3 = update(race3); - } - - @After - @Override - public void tearDown() throws Exception { - super.tearDown(); - if (dstCtxt != null && !dstCtxt.isClosed()) { - dstCtxt.closeContext(); - } - } - - @Test - @Override - public void testDetectTypes() throws Exception { - - detectTypes(race, Race.class); - detectTypes(pet, Pet.class, Person.class, Race.class); - detectTypes(person, Pet.class, Person.class, Race.class); - - detectTypes(pet2, Pet.class); - detectTypes(person2, Person.class); - detectTypes(race2, Race.class); - - detectTypes(race3, Race.class); - detectTypes(pet3, Pet.class, Race.class); - } - - @Test - @Override - public void testGetOperation() throws Exception { - - getOperation(UnregistredOperation.class, false); - getOperation(UncreatableOperation.class, true); - getOperation(FakeOperation.class, true); - getOperation(Duplicate.class, true); - getOperation(AttachAssociation.class, true); - getOperation(DettachAssociation.class, true); - } - - @Test - @Override - public void testDetectAssociations() throws Exception { - - detectAssociations(person, TopiaTestEntityEnum.Person, Person.PROPERTY_PET); - detectAssociations(race); - detectAssociations(pet); - - detectAssociations(person2); - detectAssociations(race2); - detectAssociations(pet2); - - } - - @Test - @Override - public void testDetectDirectDependencies() throws Exception { - - detectDirectDependencies(person); - detectDirectDependencies(race); - detectDirectDependencies(pet, TopiaTestEntityEnum.Pet, Pet.PROPERTY_PERSON, TopiaTestEntityEnum.Pet, Pet.PROPERTY_RACE); - - detectDirectDependencies(person2); - detectDirectDependencies(race2); - detectDirectDependencies(pet2); - } - - @Test - @Override - public void testDetectShell() throws Exception { - - detectShell(person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); - detectShell(race); - detectShell(pet, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); - detectShell(person2); - detectShell(race2); - detectShell(pet2); - } - - @Test - @Override - public void testDetectDependencies() throws Exception { - - detectDependencies(person, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); - detectDependencies(race, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}); - detectDependencies(pet, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); - - detectDependencies(person2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}); - detectDependencies(race2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}); - detectDependencies(pet2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); - } - - @Test - @Override - public void testDetectObjectsToDettach() throws Exception { - - detectObjectsToDettach(person, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); - detectObjectsToDettach(race); - detectObjectsToDettach(pet, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); - - detectObjectsToDettach(person2); - detectObjectsToDettach(race2); - detectObjectsToDettach(pet2); - - detectObjectsToDettach(race3); - detectObjectsToDettach(pet3); - } - - @Test - @Override - public void testDetectOperations() throws Exception { - - //TODO Make some real test on detected operations... - - detectOperations(person); - detectOperations(pet); - detectOperations(race); - - detectOperations(person2); - detectOperations(pet2); - detectOperations(race2); - - detectOperations(race3); - detectOperations(pet3); - } - - @Test - @Override - public void testDoReplicate() throws Exception { - - doReplicate(TopiaTestEntityEnum.Person, person); - doReplicate(TopiaTestEntityEnum.Person, person2); - doReplicate(TopiaTestEntityEnum.Person, person, person2); - - doReplicate(TopiaTestEntityEnum.Pet, pet); - doReplicate(TopiaTestEntityEnum.Pet, pet2); - doReplicate(TopiaTestEntityEnum.Pet, pet, pet2, pet3); - doReplicate(TopiaTestEntityEnum.Pet, person2, pet3); - - doReplicate(TopiaTestEntityEnum.Race, race); - doReplicate(TopiaTestEntityEnum.Race, race2); - doReplicate(TopiaTestEntityEnum.Race, race, race2); - - } - - /** - * Cette methode montre pourquoi la simple replication ne peut pas - * fonctionne :) - * <p/> - * Le replicateur ne deplique pas dans le bon ordre et on a donc des - * violations de clef etrangeres... - * - * @throws Exception pour toute erreur - */ - @Test(expected = TopiaException.class) - public void testSimpleReplicateFailed() throws Exception { - - TopiaContext dstRootCtxt = createDb2("testSimpleReplicateFailed"); - - //model = service.prepare(contracts, pet.getTopiaId()); - - TopiaContext srcCtxt = ctxt.beginTransaction(); - dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); - - try { - - srcCtxt.replicateEntity(dstCtxt, pet); - - dstCtxt.commitTransaction(); - - } finally { - srcCtxt.rollbackTransaction(); - srcCtxt.closeContext(); - dstCtxt.closeContext(); - } - } - - /** - * Cette methode montre comment manuellement on peut effectuer la - * replication (en dettachant les dependances qui forment des cycles) - * <p/> - * La methode utilisee ici peut ne pas fonctionner : si une clef metier est - * posee sur une dependance alors cela ne fonctionne pas. - * - * @throws Exception pour toute erreur - */ - @Test - public void testSimpleReplicateNotSure() throws Exception { - - TopiaContext dstRootCtxt = createDb2("testSimpleReplicateNotSure"); - - //model = service.prepare(contracts, pet.getTopiaId()); - - TopiaContext srcCtxt = ctxt; - dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); - - try { - - - srcCtxt.replicateEntity(dstCtxt, race); - - // on dettache l'entite qui pose probleme - - pet.setPerson(null); - srcCtxt.replicateEntity(dstCtxt, pet); - srcCtxt.rollbackTransaction(); - - srcCtxt.replicateEntity(dstCtxt, person); - - dstCtxt.commitTransaction(); - ((Pet) dstCtxt.findByTopiaId(pet.getTopiaId())).setPerson((Person) dstCtxt.findByTopiaId(person.getTopiaId())); - dstCtxt.commitTransaction(); - - srcCtxt.rollbackTransaction(); - person = update(person); - - assertEntityEquals(person, dstCtxt.findByTopiaId(person.getTopiaId()), null); - } finally { - srcCtxt.rollbackTransaction(); - //srcCtxt.closeContext(); - dstCtxt.closeContext(); - } - } - - /** - * Cette methode montre comment manuellement on peut effectuer la - * replication (en dettachant les associations qui forment des cycles) - * <p/> - * La methode utilisee ici fonctionne mieux que la precedante : il parrait - * dificille de pose une une clef metier sur une association :). - * <p/> - * On remarque que l'on dettache l'assocation qui forme un cycle et que l'on - * est pas obligee de la reattachee car elle est bi-directionnelle. - * <p/> - * On doit optimiser l'algorithme dans la methode {@link - * ReplicationModel#adjustOperations(org.nuiton.topia.persistence.util.TopiaEntityIdsMap)}. - * - * @throws Exception pour toute erreur - */ - @Test - public void testSimpleReplicateSure() throws Exception { - - TopiaContext dstRootCtxt = createDb2("testSimpleReplicateSure"); - - //model = service.prepare(contracts, pet.getTopiaId()); - - TopiaContext srcCtxt = ctxt; - dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); - - try { - - srcCtxt.replicateEntity(dstCtxt, race); - // on dettache l'association qui pose probleme - person.setPet(null); - srcCtxt.replicateEntity(dstCtxt, person); - - srcCtxt.replicateEntity(dstCtxt, pet); - srcCtxt.rollbackTransaction(); - dstCtxt.commitTransaction(); - - //((Person) dstCtxt.findByTopiaId(person.getTopiaId())).addPet(((Pet) dstCtxt.findByTopiaId(pet.getTopiaId()))); - //dstCtxt.commitTransaction(); - - srcCtxt.rollbackTransaction(); - - srcCtxt.closeContext(); - dstCtxt.closeContext(); - - ctxt = context.beginTransaction(); - dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); - - person = update(person); - - assertEntityEquals(person, dstCtxt.findByTopiaId(person.getTopiaId()), null); - - } finally { - dstCtxt.closeContext(); - } - } - - @Override - protected TopiaContext createDb(String name) throws Exception { - - File localDB = new File(getTestDir(getClass()), "db_" + name); - - Properties config = getH2Properties(localDB); - - context = TopiaContextFactory.getContext(config); - - TopiaContextImplementor tx = (TopiaContextImplementor) context.beginTransaction(); - - person = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding master"); - race = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race I"); - pet = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding", Pet.PROPERTY_PERSON, person, Pet.PROPERTY_RACE, race); - - person2 = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding II master"); - pet2 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding II"); - race2 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race II"); - - race3 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race III"); - pet3 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding III", Pet.PROPERTY_RACE, race3); - - tx.commitTransaction(); - tx.closeContext(); - return context; - } - - @Override - protected TopiaContext createDb2(String name) throws Exception { - - File localDB = new File(getTestDir(getClass()), "db_" + name); - - log.info("db dir :\n" + localDB.getAbsolutePath()); - - Properties config = getH2Properties(localDB); - - return TopiaContextFactory.getContext(config); - } - - @Override - protected TopiaEntityEnum[] getContracts() { - return contracts; - } - - @Override - protected Log getLog() { - return log; - } - - protected Properties getH2Properties(File f) { - - Properties config = new Properties(); - config.setProperty("hibernate.show_sql", "false"); - config.setProperty("hibernate.hbm2ddl.auto", "create"); - - config.setProperty("topia.persistence.classes", entitiesList); - config.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); - config.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); - config.setProperty("hibernate.connection.url", "jdbc:h2:file:" + f.getAbsolutePath() + "/db;create=true"); - config.setProperty("hibernate.connection.username", "sa"); - config.setProperty("hibernate.connection.password", ""); - - config.setProperty("topia.service.replication", ReplicationEngine.class.getName()); - - return config; - } -} - - Modified: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationOperationTest.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationOperationTest.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationOperationTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -54,17 +54,18 @@ import java.util.Properties; /** - * ReplicationEngineTest on model TopiaTest + * TopiaReplicationServiceImplTest on model TopiaTest * <p/> * Created: 07 jun. 09 17:14:22 * * @author tchemit <chemit@codelutin.com> * @since 2.2.0 */ -public class TopiaReplicationOperationTest extends AbstractReplicationEngineTest { +public class TopiaReplicationOperationTest extends AbstractTopiaReplicationServiceTest { - /** to use log facility, just put in your code: log.info(\"...\"); */ - private static final Log log = LogFactory.getLog(ReplicationEngineTest.class); + /** Logger */ + private static final Log log = + LogFactory.getLog(TopiaReplicationOperationTest.class); protected static final TopiaEntityEnum[] contracts = {TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race}; @@ -78,7 +79,7 @@ @AfterClass public static void after() throws Exception { - AbstractReplicationEngineTest.after(); + AbstractTopiaReplicationServiceTest.after(); } @Before @@ -106,23 +107,11 @@ @Test(expected = NullPointerException.class) public void testGetOperation_nullOperationClass() throws Exception { - service.getOperation(null); + getModelBuilder().getOperation(null); } - @Test(expected = IllegalStateException.class) - public void testGetOperation_serviceNotInit() throws Exception { -// ReplicationEngine.operations = null; - try { - new ReplicationEngine().getOperation(Duplicate.class); - } catch (IllegalStateException e) { - if (log.isErrorEnabled()) { - log.error(e); - } - throw e; - } finally { - - service.preInit((TopiaContextImplementor) context); - } + protected TopiaReplicationModelBuilder getModelBuilder() { + return service.getModelBuilder(); } @Test @@ -139,34 +128,34 @@ @Test(expected = NullPointerException.class) public void testCreateOperation_nullModel() throws Exception { - service.createOperation(null, null, null, null); + getModelBuilder().createOperation(null, null, null, null); } @Test(expected = NullPointerException.class) public void testCreateOperation_nullType() throws Exception { - model = service.createModel(contracts); - service.createOperation(model, null, null, null); + model = getModelBuilder().createModel(context, contracts); + getModelBuilder().createOperation(model, null, null, null); } @Test(expected = NullPointerException.class) public void testCreateOperation_nullPhase() throws Exception { - model = service.createModel(contracts); - service.createOperation(model, TopiaTestEntityEnum.Pet, null, null); + model = getModelBuilder().createModel(context, contracts); + getModelBuilder().createOperation(model, TopiaTestEntityEnum.Pet, null, null); } @Test(expected = NullPointerException.class) public void testCreateOperation_nullOperationClass() throws Exception { - model = service.createModel(contracts); - service.createOperation(model, TopiaTestEntityEnum.Pet, ReplicationOperationPhase.before, null); + model = getModelBuilder().createModel(context, contracts); + getModelBuilder().createOperation(model, TopiaTestEntityEnum.Pet, ReplicationOperationPhase.before, null); } @Test(expected = IllegalArgumentException.class) public void testCreateOperation_noNode() throws Exception { - model = service.createModel(contracts); + model = getModelBuilder().createModel(context, contracts); // le noeud Pet n'existe pas service.addAfterOperation(model, TopiaTestEntityEnum.Pet, Duplicate.class); } @@ -174,7 +163,7 @@ @Test(expected = IllegalArgumentException.class) public void testCreateOperation_noOperation() throws Exception { - model = service.createModel(contracts); + model = getModelBuilder().createModel(context, contracts); // le noeud Pet n'existe pas service.addAfterOperation(model, TopiaTestEntityEnum.Pet, UnregistredOperation.class); } @@ -222,35 +211,35 @@ @Test(expected = IllegalArgumentException.class) public void testCreateOperation_wrongParameterNumber() throws Exception { - model = service.createModel(contracts, pet.getTopiaId()); + model = getModelBuilder().createModel(context, contracts, pet.getTopiaId()); service.addBeforeOperation(model, TopiaTestEntityEnum.Pet, FakeOperation.class); } @Test(expected = IllegalArgumentException.class) public void testCreateOperation_wrongParameterNumber2() throws Exception { - model = service.createModel(contracts, pet.getTopiaId()); + model = getModelBuilder().createModel(context, contracts, pet.getTopiaId()); service.addBeforeOperation(model, TopiaTestEntityEnum.Pet, FakeOperation.class, String.class, String.class); } @Test(expected = IllegalArgumentException.class) public void testCreateOperation_wrongParameterType() throws Exception { - model = service.createModel(contracts, pet.getTopiaId()); + model = getModelBuilder().createModel(context, contracts, pet.getTopiaId()); service.addBeforeOperation(model, TopiaTestEntityEnum.Pet, FakeOperation.class, Integer.class); } @Test(expected = IllegalArgumentException.class) public void testCreateOperation_nullParameter() throws Exception { - model = service.createModel(contracts, pet.getTopiaId()); + model = getModelBuilder().createModel(context, contracts, pet.getTopiaId()); service.addBeforeOperation(model, TopiaTestEntityEnum.Pet, FakeOperation.class, (Object) null); } @Test public void testCreateOperation() throws Exception { - model = service.createModel(contracts, pet.getTopiaId()); + model = getModelBuilder().createModel(context, contracts, pet.getTopiaId()); service.addBeforeOperation(model, TopiaTestEntityEnum.Pet, FakeOperation.class, "before"); service.addAfterOperation(model, TopiaTestEntityEnum.Race, FakeOperation.class, "after"); } @@ -264,7 +253,7 @@ @Test(expected = NullPointerException.class) public void testDoReplicate_nullDstCtxt() throws Exception { - model = service.createModel(contracts); + model = getModelBuilder().createModel(context, contracts); service.doReplicate(model, null); } @@ -277,7 +266,8 @@ context = TopiaContextFactory.getContext(config); - TopiaContextImplementor tx = (TopiaContextImplementor) context.beginTransaction(); + TopiaContextImplementor tx = + (TopiaContextImplementor) context.beginTransaction(); person = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding master"); race = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race I"); @@ -315,7 +305,7 @@ config.setProperty("hibernate.connection.username", "sa"); config.setProperty("hibernate.connection.password", ""); - config.setProperty("topia.service.replication", ReplicationEngine.class.getName()); + config.setProperty("topia.service.replication", TopiaReplicationServiceImpl.class.getName()); return config; } Copied: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplAllTest.java (from rev 2098, trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineAllTest.java) =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplAllTest.java (rev 0) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplAllTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,296 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaContextFactory; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.TopiaTestDAOHelper.TopiaTestEntityEnum; +import org.nuiton.topia.framework.TopiaContextImplementor; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaEntityEnum; +import org.nuiton.topia.test.entities.Person; +import org.nuiton.topia.test.entities.PersonImpl; +import org.nuiton.topia.test.entities.Pet; +import org.nuiton.topia.test.entities.PetImpl; +import org.nuiton.topia.test.entities.Race; +import org.nuiton.topia.test.entities.RaceImpl; + +import java.io.File; +import java.util.Properties; + +/** + * TopiaReplicationServiceImplTest on model TopiaTest + * <p/> + * Created: 07 jun. 09 17:14:22 + * + * @author tchemit <chemit@codelutin.com> + * @since 2.2.0 + */ +public class TopiaReplicationServiceImplAllTest extends AbstractTopiaReplicationServiceTest { + + /** Logger */ + private static final Log log = LogFactory.getLog(TopiaReplicationServiceImplTest.class); + + protected static final TopiaEntityEnum[] contracts = { + TopiaTestEntityEnum.Person, + TopiaTestEntityEnum.Pet, + TopiaTestEntityEnum.Race + }; + + protected static final String entitiesList = + PersonImpl.class.getName() + "," + + PetImpl.class.getName() + "," + + RaceImpl.class.getName(); + + static protected Person person, person2; + + static protected Pet pet, pet2, pet3; + + static protected Race race, race2, race3; + + @AfterClass + public static void after() throws Exception { + AbstractTopiaReplicationServiceTest.after(); + } + + @Before + @Override + public void setUp() throws Exception { + + super.setUp(); + + person = update(person); + person2 = update(person2); + pet = update(pet); + pet2 = update(pet2); + race = update(race); + race2 = update(race2); + race3 = update(race3); + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + if (dstCtxt != null && !dstCtxt.isClosed()) { + dstCtxt.closeContext(); + } + } + +// @Ignore + + @Test + @Override + public void testDetectTypes() throws Exception { + + detectTypes(race, Race.class); + detectTypes(pet, Pet.class, Person.class, Race.class); + detectTypes(person, Pet.class, Person.class, Race.class); + + detectTypes(pet2, Pet.class); + detectTypes(person2, Person.class); + detectTypes(race2, Race.class); + + detectTypes(race3, Race.class); + detectTypes(pet3, Pet.class, Race.class); + } + +// @Ignore + + @Test + @Override + public void testGetOperation() throws Exception { + } + +// @Ignore + + @Test + @Override + public void testDetectAssociations() throws Exception { + + detectAssociations(person, TopiaTestEntityEnum.Person, Person.PROPERTY_PET); + detectAssociations(race); + detectAssociations(pet); + + detectAssociations(person2); + detectAssociations(race2); + detectAssociations(pet2); + + } + +// @Ignore + + @Test + @Override + public void testDetectDirectDependencies() throws Exception { + + detectDirectDependencies(person); + detectDirectDependencies(race); + detectDirectDependencies(pet, TopiaTestEntityEnum.Pet, Pet.PROPERTY_PERSON, TopiaTestEntityEnum.Pet, Pet.PROPERTY_RACE); + + detectDirectDependencies(person2); + detectDirectDependencies(race2); + detectDirectDependencies(pet2); + } + +// @Ignore + + @Test + @Override + public void testDetectShell() throws Exception { + + detectShell(person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); + detectShell(race); + detectShell(pet, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); + detectShell(person2, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); + detectShell(race2); + detectShell(pet2, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); + } + +// @Ignore + + @Test + @Override + public void testDetectDependencies() throws Exception { + + detectDependencies(null, + new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); + } + +// @Ignore + + @Test + @Override + public void testDetectObjectsToDettach() throws Exception { + + detectObjectsToDettach(null, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); + } + +// @Ignore + + @Test + @Override + public void testDetectOperations() throws Exception { + + detectOperations(null); + } + +// @Ignore + + @Test + @Override + public void testDoReplicate() throws Exception { + + doReplicateAll(); + + } + + @Override + protected TopiaContext createDb(String name) throws Exception { + + File localDB = new File(getTestDir(getClass()), "db_" + name); + + Properties config = getH2Properties(localDB); + + context = TopiaContextFactory.getContext(config); + + TopiaContextImplementor tx = (TopiaContextImplementor) context.beginTransaction(); + + person = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding master"); + race = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race I"); + pet = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding", Pet.PROPERTY_PERSON, person, Pet.PROPERTY_RACE, race); + + person2 = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding II master"); + pet2 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding II"); + race2 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race II"); + + race3 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race III"); + pet3 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding III", Pet.PROPERTY_RACE, race3); + + tx.commitTransaction(); + tx.closeContext(); + return context; + } + + @Override + protected TopiaContext createDb2(String name) throws Exception { + + File localDB = new File(getTestDir(getClass()), "db_" + name); + + Properties config = getH2Properties(localDB); + + return TopiaContextFactory.getContext(config); + } + + @Override + protected TopiaEntityEnum[] getContracts() { + return contracts; + } + + @Override + protected Log getLog() { + return log; + } + + protected Properties getH2Properties(File f) { + + Properties config = new Properties(); + config.setProperty("hibernate.show_sql", "false"); + config.setProperty("hibernate.hbm2ddl.auto", "create"); + + config.setProperty("topia.persistence.classes", entitiesList); + config.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + config.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); + config.setProperty("hibernate.connection.url", "jdbc:h2:file:" + f.getAbsolutePath() + ";create=true"); + config.setProperty("hibernate.connection.username", "sa"); + config.setProperty("hibernate.connection.password", ""); + + config.setProperty(TopiaReplicationServiceImpl.TOPIA_SERVICE_NAME, TopiaReplicationServiceImpl.class.getName()); + + return config; + } + + + @Override + protected void createModel(TopiaEntity entity) throws TopiaException { + model = service.getModelBuilder().createModelForAll(getContracts()); + } + + @Override + protected void prepareModel(String... ids) throws TopiaException { + model = service.prepareForAll(getContracts()); + } + +} + + Property changes on: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplAllTest.java ___________________________________________________________________ Added: svn:keywords + HeadURL Id Date Revision Author Copied: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplTest.java (from rev 2098, trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/ReplicationEngineTest.java) =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplTest.java (rev 0) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplTest.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -0,0 +1,446 @@ +/* + * #%L + * ToPIA :: Service Replication + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.topia.replication; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaContextFactory; +import org.nuiton.topia.TopiaException; +import org.nuiton.topia.TopiaTestDAOHelper.TopiaTestEntityEnum; +import org.nuiton.topia.framework.TopiaContextImplementor; +import org.nuiton.topia.persistence.TopiaEntityEnum; +import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; +import org.nuiton.topia.replication.model.ReplicationModel; +import org.nuiton.topia.replication.operation.AttachAssociation; +import org.nuiton.topia.replication.operation.DettachAssociation; +import org.nuiton.topia.replication.operation.Duplicate; +import org.nuiton.topia.replication.operation.FakeOperation; +import org.nuiton.topia.replication.operation.UncreatableOperation; +import org.nuiton.topia.replication.operation.UnregistredOperation; +import org.nuiton.topia.test.entities.Person; +import org.nuiton.topia.test.entities.PersonImpl; +import org.nuiton.topia.test.entities.Pet; +import org.nuiton.topia.test.entities.PetImpl; +import org.nuiton.topia.test.entities.Race; +import org.nuiton.topia.test.entities.RaceImpl; + +import java.io.File; +import java.util.Properties; + +/** + * TopiaReplicationServiceImplTest on model TopiaTest + * <p/> + * Created: 07 jun. 09 17:14:22 + * + * @author tchemit <chemit@codelutin.com> + * @since 2.2.0 + */ +public class TopiaReplicationServiceImplTest extends AbstractTopiaReplicationServiceTest { + + /** Logger */ + private static final Log log = LogFactory.getLog(TopiaReplicationServiceImplTest.class); + + protected static final TopiaEntityEnum[] contracts = {TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race}; + + protected static final String entitiesList = PersonImpl.class.getName() + "," + PetImpl.class.getName() + "," + RaceImpl.class.getName(); + + static protected Person person, person2; + + static protected Pet pet, pet2, pet3; + + static protected Race race, race2, race3; + + @AfterClass + public static void after() throws Exception { + AbstractTopiaReplicationServiceTest.after(); + } + + @Before + @Override + public void setUp() throws Exception { + + super.setUp(); + + person = update(person); + person2 = update(person2); + pet = update(pet); + pet2 = update(pet2); + race = update(race); + race2 = update(race2); + race3 = update(race3); + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + if (dstCtxt != null && !dstCtxt.isClosed()) { + dstCtxt.closeContext(); + } + } + + @Test + @Override + public void testDetectTypes() throws Exception { + + detectTypes(race, Race.class); + detectTypes(pet, Pet.class, Person.class, Race.class); + detectTypes(person, Pet.class, Person.class, Race.class); + + detectTypes(pet2, Pet.class); + detectTypes(person2, Person.class); + detectTypes(race2, Race.class); + + detectTypes(race3, Race.class); + detectTypes(pet3, Pet.class, Race.class); + } + + @Test + @Override + public void testGetOperation() throws Exception { + + getOperation(UnregistredOperation.class, false); + getOperation(UncreatableOperation.class, true); + getOperation(FakeOperation.class, true); + getOperation(Duplicate.class, true); + getOperation(AttachAssociation.class, true); + getOperation(DettachAssociation.class, true); + } + + @Test + @Override + public void testDetectAssociations() throws Exception { + + detectAssociations(person, TopiaTestEntityEnum.Person, Person.PROPERTY_PET); + detectAssociations(race); + detectAssociations(pet); + + detectAssociations(person2); + detectAssociations(race2); + detectAssociations(pet2); + + } + + @Test + @Override + public void testDetectDirectDependencies() throws Exception { + + detectDirectDependencies(person); + detectDirectDependencies(race); + detectDirectDependencies(pet, TopiaTestEntityEnum.Pet, Pet.PROPERTY_PERSON, TopiaTestEntityEnum.Pet, Pet.PROPERTY_RACE); + + detectDirectDependencies(person2); + detectDirectDependencies(race2); + detectDirectDependencies(pet2); + } + + @Test + @Override + public void testDetectShell() throws Exception { + + detectShell(person, TopiaTestEntityEnum.Pet, TopiaTestEntityEnum.Race); + detectShell(race); + detectShell(pet, TopiaTestEntityEnum.Person, TopiaTestEntityEnum.Race); + detectShell(person2); + detectShell(race2); + detectShell(pet2); + } + + @Test + @Override + public void testDetectDependencies() throws Exception { + + detectDependencies(person, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); + detectDependencies(race, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}); + detectDependencies(pet, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); + + detectDependencies(person2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Person}); + detectDependencies(race2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Race}); + detectDependencies(pet2, new TopiaTestEntityEnum[]{TopiaTestEntityEnum.Pet}); + } + + @Test + @Override + public void testDetectObjectsToDettach() throws Exception { + + detectObjectsToDettach(person, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); + detectObjectsToDettach(race); + detectObjectsToDettach(pet, TopiaTestEntityEnum.Person, new String[]{Person.PROPERTY_PET}); + + detectObjectsToDettach(person2); + detectObjectsToDettach(race2); + detectObjectsToDettach(pet2); + + detectObjectsToDettach(race3); + detectObjectsToDettach(pet3); + } + + @Test + @Override + public void testDetectOperations() throws Exception { + + //TODO Make some real test on detected operations... + + detectOperations(person); + detectOperations(pet); + detectOperations(race); + + detectOperations(person2); + detectOperations(pet2); + detectOperations(race2); + + detectOperations(race3); + detectOperations(pet3); + } + + @Test + @Override + public void testDoReplicate() throws Exception { + + doReplicate(TopiaTestEntityEnum.Person, person); + doReplicate(TopiaTestEntityEnum.Person, person2); + doReplicate(TopiaTestEntityEnum.Person, person, person2); + + doReplicate(TopiaTestEntityEnum.Pet, pet); + doReplicate(TopiaTestEntityEnum.Pet, pet2); + doReplicate(TopiaTestEntityEnum.Pet, pet, pet2, pet3); + doReplicate(TopiaTestEntityEnum.Pet, person2, pet3); + + doReplicate(TopiaTestEntityEnum.Race, race); + doReplicate(TopiaTestEntityEnum.Race, race2); + doReplicate(TopiaTestEntityEnum.Race, race, race2); + + } + + /** + * Cette methode montre pourquoi la simple replication ne peut pas + * fonctionne :) + * <p/> + * Le replicateur ne deplique pas dans le bon ordre et on a donc des + * violations de clef etrangeres... + * + * @throws Exception pour toute erreur + */ + @Test(expected = TopiaException.class) + public void testSimpleReplicateFailed() throws Exception { + + TopiaContext dstRootCtxt = createDb2("testSimpleReplicateFailed"); + + //model = service.prepare(contracts, pet.getTopiaId()); + + TopiaContext srcCtxt = ctxt.beginTransaction(); + dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); + + try { + + srcCtxt.replicateEntity(dstCtxt, pet); + + dstCtxt.commitTransaction(); + + } finally { + srcCtxt.rollbackTransaction(); + srcCtxt.closeContext(); + dstCtxt.closeContext(); + } + } + + /** + * Cette methode montre comment manuellement on peut effectuer la + * replication (en dettachant les dependances qui forment des cycles) + * <p/> + * La methode utilisee ici peut ne pas fonctionner : si une clef metier est + * posee sur une dependance alors cela ne fonctionne pas. + * + * @throws Exception pour toute erreur + */ + @Test + public void testSimpleReplicateNotSure() throws Exception { + + TopiaContext dstRootCtxt = createDb2("testSimpleReplicateNotSure"); + + //model = service.prepare(contracts, pet.getTopiaId()); + + TopiaContext srcCtxt = ctxt; + dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); + + try { + + + srcCtxt.replicateEntity(dstCtxt, race); + + // on dettache l'entite qui pose probleme + + pet.setPerson(null); + srcCtxt.replicateEntity(dstCtxt, pet); + srcCtxt.rollbackTransaction(); + + srcCtxt.replicateEntity(dstCtxt, person); + + dstCtxt.commitTransaction(); + ((Pet) dstCtxt.findByTopiaId(pet.getTopiaId())).setPerson((Person) dstCtxt.findByTopiaId(person.getTopiaId())); + dstCtxt.commitTransaction(); + + srcCtxt.rollbackTransaction(); + person = update(person); + + assertEntityEquals(person, dstCtxt.findByTopiaId(person.getTopiaId()), null); + } finally { + srcCtxt.rollbackTransaction(); + //srcCtxt.closeContext(); + dstCtxt.closeContext(); + } + } + + /** + * Cette methode montre comment manuellement on peut effectuer la + * replication (en dettachant les associations qui forment des cycles) + * <p/> + * La methode utilisee ici fonctionne mieux que la precedante : il parrait + * dificille de pose une une clef metier sur une association :). + * <p/> + * On remarque que l'on dettache l'assocation qui forme un cycle et que l'on + * est pas obligee de la reattachee car elle est bi-directionnelle. + * <p/> + * On doit optimiser l'algorithme dans la methode {@link + * ReplicationModel#adjustOperations(TopiaEntityIdsMap)}. + * + * @throws Exception pour toute erreur + */ + @Test + public void testSimpleReplicateSure() throws Exception { + + TopiaContext dstRootCtxt = createDb2("testSimpleReplicateSure"); + + //model = service.prepare(contracts, pet.getTopiaId()); + + TopiaContext srcCtxt = ctxt; + dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); + + try { + + srcCtxt.replicateEntity(dstCtxt, race); + // on dettache l'association qui pose probleme + person.setPet(null); + srcCtxt.replicateEntity(dstCtxt, person); + + srcCtxt.replicateEntity(dstCtxt, pet); + srcCtxt.rollbackTransaction(); + dstCtxt.commitTransaction(); + + //((Person) dstCtxt.findByTopiaId(person.getTopiaId())).addPet(((Pet) dstCtxt.findByTopiaId(pet.getTopiaId()))); + //dstCtxt.commitTransaction(); + + srcCtxt.rollbackTransaction(); + + srcCtxt.closeContext(); + dstCtxt.closeContext(); + + ctxt = context.beginTransaction(); + dstCtxt = (TopiaContextImplementor) dstRootCtxt.beginTransaction(); + + person = update(person); + + assertEntityEquals(person, dstCtxt.findByTopiaId(person.getTopiaId()), null); + + } finally { + dstCtxt.closeContext(); + } + } + + @Override + protected TopiaContext createDb(String name) throws Exception { + + File localDB = new File(getTestDir(getClass()), "db_" + name); + + Properties config = getH2Properties(localDB); + + context = TopiaContextFactory.getContext(config); + + TopiaContextImplementor tx = (TopiaContextImplementor) context.beginTransaction(); + + person = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding master"); + race = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race I"); + pet = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding", Pet.PROPERTY_PERSON, person, Pet.PROPERTY_RACE, race); + + person2 = tx.getDAO(Person.class).create(Person.PROPERTY_NAME, "pudding II master"); + pet2 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding II"); + race2 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race II"); + + race3 = tx.getDAO(Race.class).create(Race.PROPERTY_NAME, "race III"); + pet3 = tx.getDAO(Pet.class).create(Pet.PROPERTY_NAME, "pudding III", Pet.PROPERTY_RACE, race3); + + tx.commitTransaction(); + tx.closeContext(); + return context; + } + + @Override + protected TopiaContext createDb2(String name) throws Exception { + + File localDB = new File(getTestDir(getClass()), "db_" + name); + + log.info("db dir :\n" + localDB.getAbsolutePath()); + + Properties config = getH2Properties(localDB); + + return TopiaContextFactory.getContext(config); + } + + @Override + protected TopiaEntityEnum[] getContracts() { + return contracts; + } + + @Override + protected Log getLog() { + return log; + } + + protected Properties getH2Properties(File f) { + + Properties config = new Properties(); + config.setProperty("hibernate.show_sql", "false"); + config.setProperty("hibernate.hbm2ddl.auto", "create"); + + config.setProperty("topia.persistence.classes", entitiesList); + config.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); + config.setProperty("hibernate.connection.driver_class", "org.h2.Driver"); + config.setProperty("hibernate.connection.url", "jdbc:h2:file:" + f.getAbsolutePath() + "/db;create=true"); + config.setProperty("hibernate.connection.username", "sa"); + config.setProperty("hibernate.connection.password", ""); + + config.setProperty(TopiaReplicationServiceImpl.TOPIA_SERVICE_NAME, TopiaReplicationServiceImpl.class.getName()); + + return config; + } +} + + Property changes on: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/TopiaReplicationServiceImplTest.java ___________________________________________________________________ Added: svn:keywords + HeadURL Id Date Revision Author Modified: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/FakeOperation.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/FakeOperation.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/FakeOperation.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -30,8 +30,8 @@ import org.nuiton.topia.TopiaException; import org.nuiton.topia.framework.TopiaContextImplementor; import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.util.TopiaEntityHelper; import org.nuiton.topia.persistence.util.TopiaEntityIdsMap; -import org.nuiton.topia.replication.ReplicationEngine; import org.nuiton.topia.replication.TopiaReplicationOperation; import org.nuiton.topia.replication.model.ReplicationModel; import org.nuiton.topia.replication.model.ReplicationNode; @@ -46,7 +46,7 @@ */ public class FakeOperation implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(FakeOperation.class); public static final Class<?>[] PARAMETERS_CLASSES = new Class<?>[]{String.class}; @@ -57,7 +57,7 @@ ReplicationOperationPhase phase, Object... parameters) { - ReplicationEngine.checkParameters(PARAMETERS_CLASSES, parameters); + TopiaEntityHelper.checkParameters(PARAMETERS_CLASSES, parameters); ReplicationOperationDef op = new ReplicationOperationDef( phase, getClass(), Modified: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UncreatableOperation.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UncreatableOperation.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UncreatableOperation.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -47,7 +47,7 @@ */ public class UncreatableOperation implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(UncreatableOperation.class); Modified: trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UnregistredOperation.java =================================================================== --- trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UnregistredOperation.java 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/java/org/nuiton/topia/replication/operation/UnregistredOperation.java 2010-08-15 11:58:21 UTC (rev 2101) @@ -45,7 +45,7 @@ */ public class UnregistredOperation implements TopiaReplicationOperation { - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** Logger */ private static final Log log = LogFactory.getLog(UnregistredOperation.class); @Override Modified: trunk/topia-service-replication/src/test/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation =================================================================== --- trunk/topia-service-replication/src/test/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation 2010-08-15 11:51:20 UTC (rev 2100) +++ trunk/topia-service-replication/src/test/resources/META-INF/services/org.nuiton.topia.replication.TopiaReplicationOperation 2010-08-15 11:58:21 UTC (rev 2101) @@ -1,6 +1,6 @@ # # la liste des operations disponibles pour le moteur de replication -# voir la classe org.nuiton.topia.replication.ReplicationEngine +# voir la classe org.nuiton.topia.replication.TopiaReplicationServiceImpl # org.nuiton.topia.replication.operation.FakeOperation org.nuiton.topia.replication.operation.UncreatableOperation \ No newline at end of file