Resolve ALF-4739 Transfer of an item with a rule defined against it (without its associated rule) causes data corruption on destination repository

- transfer definition now allows aspects to be excluded from the transfer (setExcludedAspects)
- manifest builder is sensitive to excluded aspects
- replication definition excludes rule:rules for now

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@22513 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2010-09-14 14:59:12 +00:00
parent 652680d56a
commit 9e4ec6276f
7 changed files with 123 additions and 24 deletions

View File

@@ -58,6 +58,7 @@
<bean id="transferManifestNodeFactory" class="org.alfresco.repo.transfer.manifest.TransferManifestNodeFactoryImpl" init-method="init" > <bean id="transferManifestNodeFactory" class="org.alfresco.repo.transfer.manifest.TransferManifestNodeFactoryImpl" init-method="init" >
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="permissionService" ref="PermissionService" /> <property name="permissionService" ref="PermissionService" />
<property name="dictionaryService" ref="DictionaryService" />
</bean> </bean>
<bean id="alienProcessor" class="org.alfresco.repo.transfer.AlienProcessorImpl" <bean id="alienProcessor" class="org.alfresco.repo.transfer.AlienProcessorImpl"

View File

@@ -27,6 +27,7 @@ import org.alfresco.repo.action.ActionCancelledException;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.repo.lock.JobLockService; import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transfer.ChildAssociatedNodeFinder; import org.alfresco.repo.transfer.ChildAssociatedNodeFinder;
import org.alfresco.repo.transfer.ContentClassFilter; import org.alfresco.repo.transfer.ContentClassFilter;
@@ -169,14 +170,19 @@ public class ReplicationActionExecutor extends ActionExecuterAbstractBase {
* replication to be run. * replication to be run.
*/ */
protected TransferDefinition buildTransferDefinition( protected TransferDefinition buildTransferDefinition(
ReplicationDefinition replicationDef, Set<NodeRef> toTransfer ReplicationDefinition replicationDef, Set<NodeRef> toTransfer)
) { {
TransferDefinition transferDefinition = TransferDefinition transferDefinition =
new TransferDefinition(); new TransferDefinition();
transferDefinition.setNodes(toTransfer); transferDefinition.setNodes(toTransfer);
transferDefinition.setSync(true); transferDefinition.setSync(true);
transferDefinition.setReadOnly(true); transferDefinition.setReadOnly(true);
// Exclude aspects from transfer
// NOTE: this list of aspects should be synced up with the NodeCrawler in expandPayload to
// ensure a coherent set of nodes are transferred
transferDefinition.setExcludedAspects(RuleModel.ASPECT_RULES);
return transferDefinition; return transferDefinition;
} }
@@ -209,10 +215,6 @@ public class ReplicationActionExecutor extends ActionExecuterAbstractBase {
throw new ReplicationServiceException("Unable to execute a disabled replication definition"); throw new ReplicationServiceException("Unable to execute a disabled replication definition");
} }
// Clear the previous transfer report references
// replicationDef.setLocalTransferReport(null);
// replicationDef.setRemoteTransferReport(null);
// Lock the service - only one instance of the replication // Lock the service - only one instance of the replication
// should occur at a time // should occur at a time
ReplicationDefinitionLockExtender lock = ReplicationDefinitionLockExtender lock =

View File

@@ -909,7 +909,7 @@ public class TransferServiceImpl2 implements TransferService2
formatter.writeTransferManifestHeader(header); formatter.writeTransferManifestHeader(header);
for(NodeRef nodeRef : nodes) for(NodeRef nodeRef : nodes)
{ {
TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef); TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef, definition);
formatter.writeTransferManifestNode(node); formatter.writeTransferManifestNode(node);
} }
formatter.endTransferManifest(); formatter.endTransferManifest();

View File

@@ -31,6 +31,7 @@ import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
@@ -69,9 +70,9 @@ public class UnitTestTransferManifestNodeFactory implements TransferManifestNode
this.realFactory = realFactory; this.realFactory = realFactory;
} }
public TransferManifestNode createTransferManifestNode(NodeRef nodeRef) public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition)
{ {
TransferManifestNode newNode = realFactory.createTransferManifestNode(nodeRef); TransferManifestNode newNode = realFactory.createTransferManifestNode(nodeRef, definition);
NodeRef origNodeRef = newNode.getNodeRef(); NodeRef origNodeRef = newNode.getNodeRef();

View File

@@ -19,8 +19,9 @@
package org.alfresco.repo.transfer.manifest; package org.alfresco.repo.transfer.manifest;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.TransferDefinition;
public interface TransferManifestNodeFactory public interface TransferManifestNodeFactory
{ {
TransferManifestNode createTransferManifestNode(NodeRef nodeRef); TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition);
} }

View File

@@ -18,11 +18,17 @@
*/ */
package org.alfresco.repo.transfer.manifest; package org.alfresco.repo.transfer.manifest;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -30,7 +36,9 @@ import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.transfer.TransferDefinition;
import org.alfresco.service.cmr.transfer.TransferException; import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
/** /**
@@ -43,15 +51,16 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
{ {
private NodeService nodeService; private NodeService nodeService;
private PermissionService permissionService; private PermissionService permissionService;
private DictionaryService dictionaryService;
public void init() public void init()
{ {
} }
public TransferManifestNode createTransferManifestNode(NodeRef nodeRef) public TransferManifestNode createTransferManifestNode(NodeRef nodeRef, TransferDefinition definition)
{ {
NodeRef.Status status = nodeService.getNodeStatus(nodeRef); NodeRef.Status status = nodeService.getNodeStatus(nodeRef);
if(status == null) if(status == null)
{ {
@@ -104,9 +113,9 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
TransferManifestNormalNode node = new TransferManifestNormalNode(); TransferManifestNormalNode node = new TransferManifestNormalNode();
node.setNodeRef(nodeRef); node.setNodeRef(nodeRef);
node.setProperties(nodeService.getProperties(nodeRef)); node.setProperties(getNodeProperties(nodeRef, definition == null ? null : definition.getExcludedAspects()));
node.setAspects(nodeService.getAspects(nodeRef)); node.setAspects(getNodeAspects(nodeRef, definition == null ? null : definition.getExcludedAspects()));
node.setType(nodeService.getType(nodeRef)); node.setType(nodeService.getType(nodeRef));
ChildAssociationRef parentAssocRef = nodeService.getPrimaryParent(nodeRef); ChildAssociationRef parentAssocRef = nodeService.getPrimaryParent(nodeRef);
if(parentAssocRef != null && parentAssocRef.getParentRef() != null) if(parentAssocRef != null && parentAssocRef.getParentRef() != null)
{ {
@@ -145,25 +154,76 @@ public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFact
return node; return node;
} }
} }
/**
* Gets the aspects of the specified node, minus those that have been explicitly excluded
*
* @param nodeRef node to get aspects for
* @param excludedAspects aspects to exluce
* @return set of aspects minus those excluded
*/
private Set<QName> getNodeAspects(NodeRef nodeRef, Set<QName> excludedAspects)
{
Set<QName> aspects = nodeService.getAspects(nodeRef);
if (excludedAspects == null || excludedAspects.size() == 0)
{
return aspects;
}
else
{
Set<QName> filteredAspects = new HashSet<QName>(aspects.size());
for (QName aspect : aspects)
{
if (!excludedAspects.contains(aspect))
{
filteredAspects.add(aspect);
}
}
return filteredAspects;
}
}
/**
* Gets the properties of the specified node, minus those that have been explicitly excluded
*
* @param nodeRef node to get aspects for
* @param excludedAspects aspects to exluce
* @return map of properties minus those excluded
*/
private Map<QName, Serializable> getNodeProperties(NodeRef nodeRef, Set<QName> excludedAspects)
{
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
if (excludedAspects == null || excludedAspects.size() == 0)
{
return properties;
}
else
{
Map<QName, Serializable> filteredProperties = new HashMap<QName, Serializable>(properties.size());
for (Map.Entry<QName, Serializable> property : properties.entrySet())
{
PropertyDefinition propDef = dictionaryService.getProperty(property.getKey());
if (propDef == null || !excludedAspects.contains(propDef.getContainerClass().getName()))
{
filteredProperties.put(property.getKey(), property.getValue());
}
}
return filteredProperties;
}
}
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
public NodeService getNodeService()
{
return nodeService;
}
public void setPermissionService(PermissionService permissionService) public void setPermissionService(PermissionService permissionService)
{ {
this.permissionService = permissionService; this.permissionService = permissionService;
} }
public PermissionService getPermissionService() public void setDictionaryService(DictionaryService dictionaryService)
{ {
return permissionService; this.dictionaryService = dictionaryService;
} }
} }

View File

@@ -25,6 +25,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/** /**
* Definition of what to transfer. * Definition of what to transfer.
@@ -47,6 +48,9 @@ public class TransferDefinition implements Serializable
// Which nodes to deploy // Which nodes to deploy
private Set<NodeRef> nodes; private Set<NodeRef> nodes;
// Which aspects to exclude
private Set<QName> excludedAspects;
/** /**
* isSync specifies whether the list of nodes is to be sync'ed. If sync then the transfer * isSync specifies whether the list of nodes is to be sync'ed. If sync then the transfer
@@ -73,7 +77,7 @@ public class TransferDefinition implements Serializable
public void setNodes(NodeRef...nodes) public void setNodes(NodeRef...nodes)
{ {
this.setNodes(new HashSet<NodeRef>(Arrays.asList(nodes))); this.setNodes(Arrays.asList(nodes));
} }
/** /**
@@ -84,6 +88,36 @@ public class TransferDefinition implements Serializable
{ {
return nodes; return nodes;
} }
/**
* Sets which aspects to exclude from transfer
*
* @param exludedAspects collection of aspects to exclude
*/
public void setExcludedAspects(Collection<QName> exludedAspects)
{
this.excludedAspects = new HashSet<QName>(exludedAspects);
}
/**
* Sets which aspects to exclude from transfer
*
* @param excludedAspects aspects to exclude from transfer
*/
public void setExcludedAspects(QName... excludedAspects)
{
this.setExcludedAspects(Arrays.asList(excludedAspects));
}
/**
* Gets the aspects to exclude from transfer
*
* @return set of excluded aspects (or null, if none specified)
*/
public Set<QName> getExcludedAspects()
{
return excludedAspects;
}
/** /**
* isSync specifies whether the list of nodes is to be sync'ed. If sync then the transfer * isSync specifies whether the list of nodes is to be sync'ed. If sync then the transfer