use of org.alfresco.repo.copy.CopyBehaviourCallback.AssocCopyTargetAction in project alfresco-repository by Alfresco.
the class CopyServiceImpl method copyPendingAssociations.
/**
* Copy any remaining associations that could not be copied or ignored during the copy process.
* See <a href=http://issues.alfresco.com/jira/browse/ALF-958>ALF-958: Target associations aren't copied</a>.
*/
private void copyPendingAssociations(Map<NodeRef, NodeRef> copiedNodeRefs) {
// Prepare storage for post-copy association handling
List<Pair<AssociationRef, AssocCopyTargetAction>> postCopyAssocs = TransactionalResourceHelper.getList(KEY_POST_COPY_ASSOCS);
for (Pair<AssociationRef, AssocCopyTargetAction> pair : postCopyAssocs) {
AssociationRef assocRef = pair.getFirst();
AssocCopyTargetAction action = pair.getSecond();
// Was the original target copied?
NodeRef newSourceForAssoc = copiedNodeRefs.get(assocRef.getSourceRef());
if (newSourceForAssoc == null) {
// Developer #fail
throw new IllegalStateException("Post-copy association has a source that was NOT copied.");
}
NodeRef oldTargetForAssoc = assocRef.getTargetRef();
// May be null
NodeRef newTargetForAssoc = copiedNodeRefs.get(oldTargetForAssoc);
QName assocTypeQName = assocRef.getTypeQName();
switch(action) {
case USE_ORIGINAL_TARGET:
internalNodeService.createAssociation(newSourceForAssoc, oldTargetForAssoc, assocTypeQName);
break;
case USE_COPIED_TARGET:
// Do nothing if the target was not copied
if (newTargetForAssoc != null) {
internalNodeService.createAssociation(newSourceForAssoc, newTargetForAssoc, assocTypeQName);
}
break;
case USE_COPIED_OTHERWISE_ORIGINAL_TARGET:
if (newTargetForAssoc == null) {
internalNodeService.createAssociation(newSourceForAssoc, oldTargetForAssoc, assocTypeQName);
} else {
internalNodeService.createAssociation(newSourceForAssoc, newTargetForAssoc, assocTypeQName);
}
break;
default:
throw new IllegalStateException("Unknown association action: " + action);
}
}
}
use of org.alfresco.repo.copy.CopyBehaviourCallback.AssocCopyTargetAction in project alfresco-repository by Alfresco.
the class CopyServiceImpl method copyChildren.
/**
* @param copyChildren <tt>false</tt> if the client selected not to recurse
*/
private void copyChildren(CopyDetails copyDetails, QName classQName, NodeRef copyTarget, boolean copyTargetIsNew, boolean copyChildren, Map<NodeRef, NodeRef> copiesByOriginals, Set<NodeRef> copies, Map<QName, CopyBehaviourCallback> callbacks) {
NodeRef sourceNodeRef = copyDetails.getSourceNodeRef();
ClassDefinition classDef = dictionaryService.getClass(classQName);
if (classDef == null) {
// Ignore missing types
return;
}
// Check the behaviour
CopyBehaviourCallback callback = callbacks.get(classQName);
if (callback == null) {
throw new IllegalStateException("Source node class has no callback: " + classQName);
}
// Prepare storage for post-copy association handling
List<Pair<AssociationRef, AssocCopyTargetAction>> postCopyAssocs = TransactionalResourceHelper.getList(KEY_POST_COPY_ASSOCS);
// Handle peer associations.
for (Map.Entry<QName, AssociationDefinition> entry : classDef.getAssociations().entrySet()) {
QName assocTypeQName = entry.getKey();
AssociationDefinition assocDef = entry.getValue();
if (assocDef.isChild()) {
// Ignore child assocs
continue;
}
boolean haveRemovedFromCopyTarget = false;
// Get the associations
List<AssociationRef> assocRefs = nodeService.getTargetAssocs(sourceNodeRef, assocTypeQName);
for (AssociationRef assocRef : assocRefs) {
// Get the copy action for the association instance
CopyAssociationDetails assocCopyDetails = new CopyAssociationDetails(assocRef, copyTarget, copyTargetIsNew);
Pair<AssocCopySourceAction, AssocCopyTargetAction> assocCopyAction = callback.getAssociationCopyAction(classQName, copyDetails, assocCopyDetails);
// Consider the source side first
switch(assocCopyAction.getFirst()) {
case IGNORE:
// Do nothing
continue;
case COPY_REMOVE_EXISTING:
if (!copyTargetIsNew && !haveRemovedFromCopyTarget) {
// Only do this if we are copying over an existing node and we have NOT
// already cleaned up for this association type
haveRemovedFromCopyTarget = true;
for (AssociationRef assocToRemoveRef : internalNodeService.getTargetAssocs(copyTarget, assocTypeQName)) {
internalNodeService.removeAssociation(assocToRemoveRef.getSourceRef(), assocToRemoveRef.getTargetRef(), assocTypeQName);
}
}
// Fall through to copy
case COPY:
// Record the type of target behaviour that is expected
switch(assocCopyAction.getSecond()) {
case USE_ORIGINAL_TARGET:
case USE_COPIED_TARGET:
case USE_COPIED_OTHERWISE_ORIGINAL_TARGET:
// Have to save for later to see if the target node is copied, too
postCopyAssocs.add(new Pair<AssociationRef, AssocCopyTargetAction>(assocRef, assocCopyAction.getSecond()));
break;
default:
throw new IllegalStateException("Unknown association target copy action: " + assocCopyAction);
}
break;
default:
throw new IllegalStateException("Unknown association source copy action: " + assocCopyAction);
}
}
}
// Handle child associations. These need special attention due to their recursive nature.
for (Map.Entry<QName, ChildAssociationDefinition> childEntry : classDef.getChildAssociations().entrySet()) {
QName childAssocTypeQName = childEntry.getKey();
ChildAssociationDefinition childAssocDef = childEntry.getValue();
if (!childAssocDef.isChild()) {
// Ignore non-child assocs
continue;
}
// Get the child associations
List<ChildAssociationRef> childAssocRefs = nodeService.getChildAssocs(sourceNodeRef, childAssocTypeQName, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef childAssocRef : childAssocRefs) {
NodeRef childNodeRef = childAssocRef.getChildRef();
QName assocQName = childAssocRef.getQName();
CopyChildAssociationDetails childAssocCopyDetails = new CopyChildAssociationDetails(childAssocRef, copyTarget, copyTargetIsNew, copyChildren);
// Handle nested copies
if (copies.contains(childNodeRef)) {
// of the same type. This is ignorable.
continue;
}
// Get the copy action for the association instance
ChildAssocCopyAction childAssocCopyAction = callback.getChildAssociationCopyAction(classQName, copyDetails, childAssocCopyDetails);
switch(childAssocCopyAction) {
case IGNORE:
break;
case COPY_ASSOC:
nodeService.addChild(copyTarget, childNodeRef, childAssocTypeQName, assocQName);
break;
case COPY_CHILD:
// Handle potentially cyclic relationships
if (copiesByOriginals.containsKey(childNodeRef)) {
// This is either a cyclic relationship or there are multiple different
// types of associations between the same parent and child.
// Just hook the child up with the association.
nodeService.addChild(copyTarget, childNodeRef, childAssocTypeQName, assocQName);
} else {
// Find out whether to force a recursion
ChildAssocRecurseAction childAssocRecurseAction = callback.getChildAssociationRecurseAction(classQName, copyDetails, childAssocCopyDetails);
switch(childAssocRecurseAction) {
case RESPECT_RECURSE_FLAG:
// Keep child copy flag the same
break;
case FORCE_RECURSE:
// Force recurse
copyChildren = true;
break;
default:
throw new IllegalStateException("Unrecognized enum");
}
// This copy may fail silently
copyImpl(childNodeRef, copyTarget, childAssocTypeQName, assocQName, // Keep child names for deep copies
copyChildren, // Keep child names for deep copies
false, copiesByOriginals, copies);
}
break;
default:
throw new IllegalStateException("Unrecognized enum");
}
}
}
}
Aggregations