mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -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"
|
||||||
|
@@ -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 =
|
||||||
|
@@ -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();
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user