Files
alfresco-community-repo/source/java/org/alfresco/repo/transfer/AlienProcessorImpl.java
Alan Davis 84841e063f Merged 5.2.N (5.2.1) to HEAD (5.2)
125788 rmunteanu: Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
      125606 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
         125515 slanglois: MNT-16155 Update source headers - add new Copyrights for Java and JSP source files + automatic check in the build


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127810 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2016-06-03 17:08:06 +00:00

1028 lines
45 KiB
Java

/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco 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.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.transfer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Class to encapsulate the behaviour of "Alien" nodes.
*/
public class AlienProcessorImpl implements AlienProcessor
{
private NodeService nodeService;
private BehaviourFilter behaviourFilter;
private DictionaryService dictionaryService;
private DescriptorService descriptorService;
private static final Log log = LogFactory.getLog(AlienProcessorImpl.class);
public void init()
{
PropertyCheck.mandatory(this, "nodeService", nodeService);
PropertyCheck.mandatory(this, "behaviourFilter", behaviourFilter);
PropertyCheck.mandatory(this, "dictionaryService", getDictionaryService());
PropertyCheck.mandatory(this, "descriptorService", descriptorService);
}
public void onCreateChild(ChildAssociationRef childAssocRef, final String repositoryId, boolean isNewNode)
{
log.debug("on create child association to transferred node");
ChildAssociationRef currentAssoc = childAssocRef;
NodeRef parentNodeRef = currentAssoc.getParentRef();
NodeRef childNodeRef = currentAssoc.getChildRef();
if(!childAssocRef.isPrimary())
{
log.debug("not a primary assoc - do nothing");
return;
}
/**
* check assoc is a cm:contains or subtype of cm:contains
*/
if(!childAssocRef.getTypeQName().equals(ContentModel.ASSOC_CONTAINS))
{
Collection<QName> subAspects = dictionaryService.getSubAspects(ContentModel.ASSOC_CONTAINS, true);
if(!subAspects.contains(childAssocRef.getTypeQName()))
{
log.debug("not a subtype of cm:contains - do nothing");
return;
}
}
if(!(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN)))
{
log.debug("parent was not transferred or alien - do nothing");
return;
}
if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
// parent is not yet an alien invader ...
String parentFromRepo = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
{
if(repositoryId.equalsIgnoreCase(parentFromRepo))
{
log.debug("parent was not alien and this node is from the same repo - do nothing");
return;
}
}
}
/**
* If we get this far then we are going to Make the new child node
* an alien node
*/
setAlien(childNodeRef, repositoryId);
/**
* Now deal with the parents of this alien node
*/
while(currentAssoc != null)
{
parentNodeRef = currentAssoc.getParentRef();
childNodeRef = currentAssoc.getChildRef();
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
if (!isInvaded(parentNodeRef, repositoryId))
{
if(log.isDebugEnabled())
{
log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + repositoryId);
}
final NodeRef newAlien = parentNodeRef;
/**
* Parent may be locked or not be editable by the current user
* turn off auditing and lock service for this transaction and
* run as admin.
*/
RunAsWork<Void> actionRunAs = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE);
getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE);
setAlien(newAlien, repositoryId);
return null;
}
};
AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName());
// Yes the parent has been invaded so step up to the parent's parent
currentAssoc = nodeService.getPrimaryParent(parentNodeRef);
}
else
{
log.debug("parent node is already invaded");
currentAssoc = null;
}
}
else
{
log.debug("parent is not a transferred node");
currentAssoc = null;
}
}
if (log.isTraceEnabled())
{
logInvasionHierarchy(childAssocRef.getParentRef(), childAssocRef.getChildRef());
}
}
/**
* Puts information about current <code>childRef</code> and its <code>parentRef</code> into log in TRACE level. Information includes 'name', 'fromRepositoryId', 'aliened' and
* 'invadedBy' properties. Additionally, collects the same information for children of <code>childRef</code>
*
* @param parentRef - {@link NodeRef} instance of child node
* @param childRef - {@link NodeRef} instance of parent of the <code>childRef</code>
*/
protected void logInvasionHierarchy(NodeRef parentRef, NodeRef childRef)
{
Map<QName, Serializable> properties = nodeService.getProperties(childRef);
Map<QName, Serializable> parentProperties = nodeService.getProperties(parentRef);
StringBuilder message = new StringBuilder("Information about '").append(properties.get(ContentModel.PROP_NAME)).append("' node:\n fromRepositoryId: ").append(
properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)).append("\n").append(" invadedBy: ").append(properties.get(TransferModel.PROP_INVADED_BY)).append("\n")
.append(" alien: ").append(nodeService.hasAspect(childRef, TransferModel.ASPECT_ALIEN)).append("\n").append(" repositoryId: ").append(
properties.get(TransferModel.PROP_REPOSITORY_ID)).append("\n").append(" parent: ").append(parentProperties.get(ContentModel.PROP_NAME)).append("(")
.append(parentProperties.get(TransferModel.PROP_FROM_REPOSITORY_ID)).append(")").append(parentProperties.get(TransferModel.PROP_INVADED_BY)).append(": ").append(
nodeService.hasAspect(parentRef, TransferModel.ASPECT_ALIEN)).append("\n").append(" children:\n");
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(childRef);
if ((null != childAssocs) && !childAssocs.isEmpty())
{
for (ChildAssociationRef child : childAssocs)
{
properties = nodeService.getProperties(child.getChildRef());
message.append(" ").append(properties.get(ContentModel.PROP_NAME)).append("(").append(properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)).append(")")
.append(properties.get(TransferModel.PROP_INVADED_BY)).append(": ").append(nodeService.hasAspect(child.getChildRef(), TransferModel.ASPECT_ALIEN)).append(
"\n");
}
}
log.trace(message.toString());
}
public void beforeDeleteAlien(NodeRef deletedNodeRef, ChildAssociationRef oldAssoc)
{
log.debug("before delete node - need to check for alien invaders");
List<String>stuff = (List<String>)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY);
if (stuff == null) return;
Vector<String> exInvaders = new Vector<String>(stuff);
/**
* some fudge to get this to run after the node has been moved.
*/
ChildAssociationRef currentAssoc;
if(oldAssoc != null)
{
currentAssoc = oldAssoc;
}
else
{
currentAssoc = nodeService.getPrimaryParent(deletedNodeRef);
}
while(currentAssoc != null && exInvaders != null && exInvaders.size() > 0)
{
NodeRef parentNodeRef = currentAssoc.getParentRef();
NodeRef currentNodeRef;
if(currentAssoc == oldAssoc)
{
currentNodeRef = deletedNodeRef;
}
else
{
currentNodeRef = currentAssoc.getChildRef();
}
/**
* Does the parent have alien invaders ?
*/
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
log.debug("parent node is invaded by aliens");
/**
* Remove the parent's origin from the list of exInvaders since the parent also invades.
*/
String parentRepoId;
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
parentRepoId = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
}
else
{
parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId();
}
exInvaders.remove(parentRepoId);
/**
* For each invader of the deletedNode
*/
Iterator<String> i = exInvaders.listIterator();
while(i.hasNext())
{
String exInvader = i.next();
log.debug("Checking exInvader:" + exInvader);
/**
* Check the siblings of this node to see whether there are any other alien nodes for this invader.
*/
//List<ChildAssociationRef> refs = nodeService.getChildAssocs(parentNodeRef);
List<ChildAssociationRef> refs = nodeService.getChildAssocsByPropertyValue(parentNodeRef, TransferModel.PROP_INVADED_BY, exInvader);
for(ChildAssociationRef ref : refs)
{
NodeRef childRef = ref.getChildRef();
List<String>invadedBy = (List<String>)nodeService.getProperty(childRef, TransferModel.PROP_INVADED_BY);
if(childRef.equals(currentNodeRef))
{
// do nothing - this is the node we are working with.
}
else
{
if(invadedBy != null && invadedBy.contains(exInvader))
{
// There is a sibling so remove this from the list of ex invaders.
log.debug("yes there is a sibling so it remains an invader");
i.remove();
break;
}
}
} // for each child assoc
} // for each invader
log.debug("end of checking siblings");
if(exInvaders.size() > 0)
{
log.debug("removing invaders from parent node:" + parentNodeRef);
List<String> parentInvaders = (List<String>)nodeService.getProperty(parentNodeRef, TransferModel.PROP_INVADED_BY);
final List<String> newInvaders = new ArrayList<String>(10);
for(String invader : parentInvaders)
{
if(exInvaders.contains(invader))
{
log.debug("removing invader:" + invader);
}
else
{
newInvaders.add(invader);
}
}
final NodeRef oldAlien = parentNodeRef;
/**
* Parent may be locked or not be editable by the current user
* turn off auditing and lock service for this transaction and
* run as admin.
*/
RunAsWork<Void> actionRunAs = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
behaviourFilter.disableBehaviour(oldAlien, ContentModel.ASPECT_AUDITABLE);
behaviourFilter.disableBehaviour(oldAlien, ContentModel.ASPECT_LOCKABLE);
if(newInvaders.size() > 0)
{
nodeService.setProperty(oldAlien, TransferModel.PROP_INVADED_BY, (Serializable)newInvaders);
}
else
{
log.debug("parent node is no longer alien nodeRef" + oldAlien);
nodeService.removeAspect(oldAlien, TransferModel.ASPECT_ALIEN);
}
return null;
}
};
AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName());
}
/**
* Now step up to the parent's parent
*/
currentAssoc = nodeService.getPrimaryParent(parentNodeRef);
}
else
{
log.debug("parent is not an alien node");
currentAssoc = null;
}
} // end of while
}
public void afterMoveAlien(ChildAssociationRef newAssocRef)
{
log.debug("after move alien: newAssocRef");
NodeRef parentNodeRef = newAssocRef.getParentRef();
NodeRef childNodeRef = newAssocRef.getChildRef();
List<String> childInvadedBy = (List<String>)nodeService.getProperty(childNodeRef, TransferModel.PROP_INVADED_BY);
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
List<String>aliensToAdd = new ArrayList<String>();
log.debug("new parent is transferred or alien");
/**
* check assoc is a cm:contains or subtype of cm:contains
*/
if(!newAssocRef.getTypeQName().equals(ContentModel.ASSOC_CONTAINS))
{
Collection<QName> subAspects = dictionaryService.getSubAspects(ContentModel.ASSOC_CONTAINS, true);
if(!subAspects.contains(newAssocRef.getTypeQName()))
{
log.debug("not a subtype of cm:contains - may need to uninvade");
String parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId();
retreatDownwards(childNodeRef, parentRepoId);
return;
}
}
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
// parent is already alien
List<String>parentInvadedBy = (List<String>)nodeService.getProperty(parentNodeRef, TransferModel.PROP_INVADED_BY);
for(String invader : childInvadedBy)
{
if(!parentInvadedBy.contains(invader))
{
aliensToAdd.add(invader);
}
}
}
else
{
// parent is transfered but does not yet contain aliens
String parentFromRepo = (String)nodeService.getProperty(parentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
{
for(String invader : childInvadedBy)
{
if(invader.equalsIgnoreCase(parentFromRepo))
{
// The invader is the same repo
log.debug("child node is from the same repo as a non invaded node");
retreatDownwards(childNodeRef, parentFromRepo);
}
else
{
aliensToAdd.add(invader);
}
}
}
}
/**
* Now deal with the parents of this alien node
*/
ChildAssociationRef currentAssoc = newAssocRef;
while(currentAssoc != null && aliensToAdd.size() > 0)
{
parentNodeRef = currentAssoc.getParentRef();
childNodeRef = currentAssoc.getChildRef();
// if parent node is transferred or alien
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED) || nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
Iterator<String> i = aliensToAdd.iterator();
// for each alien repo id to add
while(i.hasNext())
{
String alienRepoId = (String)i.next();
if (!isInvaded(parentNodeRef, alienRepoId))
{
if(log.isDebugEnabled())
{
log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + alienRepoId);
}
final NodeRef newAlien = parentNodeRef;
final String fAlien = alienRepoId;
/**
* Parent may be locked or not be editable by the current user
* turn off auditing and lock service for this transaction and
* run as admin.
*/
RunAsWork<Void> actionRunAs = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE);
getBehaviourFilter().disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE);
setAlien(newAlien, fAlien);
return null;
}
};
AuthenticationUtil.runAs(actionRunAs, AuthenticationUtil.getSystemUserName());
}
else
{
log.debug("parent node is already invaded by:" + alienRepoId);
i.remove();
}
// Yes the parent has been invaded so step up to the parent's parent
currentAssoc = nodeService.getPrimaryParent(parentNodeRef);
}
}
else
{
log.debug("parent is not a transferred node");
currentAssoc = null;
}
}
}
else
{
log.debug("parent was not transferred or alien");
String parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId();
retreatDownwards(childNodeRef, parentRepoId);
return;
}
} // after move alien
/**
* Top down un-invasion
* <p>
* Steps down the tree retreating from all the invaded nodes.
* <p>
* The retreat will stop is there is a "sub-invasion".
* <p>
* @param nodeRef the top of the tree
* @param fromRepositoryId the repository that is retreating.
*/
private void retreatDownwards(NodeRef nodeRef, String fromRepositoryId)
{
Stack<NodeRef> nodesToRetreat = new Stack<NodeRef>();
nodesToRetreat.add(nodeRef);
/**
* Now go and do the retreat.
*/
while(!nodesToRetreat.isEmpty())
{
if(log.isDebugEnabled())
{
log.debug("retreat :" + nodeRef + ", repoId:" + fromRepositoryId);
}
/**
* for the current node and all alien children
*
* if they are "from" the retreating repository then
*/
NodeRef currentNodeRef = nodesToRetreat.pop();
log.debug("retreatNode:" + currentNodeRef);
if(getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN))
{
// Yes this is an alien node
List<String>invadedBy = (List<String>)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY);
String parentRepoId;
if(nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
log.debug("node is transferred");
parentRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
}
else
{
log.debug("node is local");
parentRepoId = descriptorService.getCurrentRepositoryDescriptor().getId();
}
if(fromRepositoryId.equalsIgnoreCase(parentRepoId))
{
// This node is "owned" by the retreating repo
// Yes we are invaded by fromRepositoryId
if(invadedBy.size() == 1)
{
// we are invaded by a single repository which must be fromRepositoryId
log.debug("no longe alien:" + currentNodeRef);
getNodeService().removeAspect(currentNodeRef, TransferModel.ASPECT_ALIEN);
}
else
{
invadedBy.remove(parentRepoId);
getNodeService().setProperty(currentNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)invadedBy);
}
//List<ChildAssociationRef> refs = getNodeService().getChildAssocs(currentNodeRef);
List<ChildAssociationRef> refs = nodeService.getChildAssocsByPropertyValue(currentNodeRef, TransferModel.PROP_INVADED_BY, fromRepositoryId);
for(ChildAssociationRef ref : refs)
{
if(log.isDebugEnabled())
{
log.debug("will need to check child:" + ref);
}
nodesToRetreat.push(ref.getChildRef());
}
}
}
}
} // retreatDownwards
public boolean isAlien(NodeRef nodeRef)
{
return nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ALIEN);
}
public void pruneNode(NodeRef nodeToPrune, String fromRepositoryId)
{
Stack<NodeRef> nodesToPrune = new Stack<NodeRef>();
nodesToPrune.add(nodeToPrune);
ChildAssociationRef startingParent = nodeService.getPrimaryParent(nodeToPrune);
Stack<NodeRef> foldersToRecalculate = new Stack<NodeRef>();
/**
* Now go and do the pruning.
*/
while(!nodesToPrune.isEmpty())
{
/**
* for all alien children
*
* if from the repo with no (other) aliens - delete
*
* if from the repo with multiple alien invasions - leave alone but process children
*/
NodeRef currentNodeRef = nodesToPrune.pop();
Map<QName, Serializable> properties = null;
if (log.isDebugEnabled())
{
properties = nodeService.getProperties(currentNodeRef);
}
if (log.isDebugEnabled())
{
log.debug("Current nodeRef (name: \"" + properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")" + currentNodeRef);
}
log.debug("pruneNode:" + currentNodeRef);
if(getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN))
{
if (log.isDebugEnabled())
{
log.debug("Current nodeRef has ASPECT_ALIEN (name: \"" + properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \""
+ properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\")");
}
// Yes this is an alien node
List<String> invadedBy = (List<String>)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY);
String initialRepoId = (String) getNodeService().getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
if (log.isDebugEnabled())
{
log.debug("Current nodeRef has PROP_INVADED_BY (name: \"" + properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \""
+ properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\"): " + invadedBy);
}
if ((null != invadedBy) && invadedBy.contains(fromRepositoryId))
{
if (log.isDebugEnabled())
{
log.debug("Current nodeRef's PROP_INVADED_BY contains current manifestId (name: \"" + properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \""
+ properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\")");
}
// Yes we are invaded by fromRepositoryId
if ((1 == invadedBy.size()) && fromRepositoryId.equalsIgnoreCase(initialRepoId))
{
if (log.isDebugEnabled())
{
log
.debug("Current nodeRef has only 1 element in PROP_INVADED_BY. Also MANIFEST_ID and INITIAL_REPOSITORY_ID are the same. Deleting the node... (name: \""
+ properties.get(ContentModel.PROP_NAME)
+ "\", fromRepositoryId: \""
+ properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")");
}
// we are invaded by a single repository which must be fromRepositoryId
getNodeService().deleteNode(currentNodeRef);
}
else
{
if (log.isDebugEnabled())
{
log.debug("Current 'nodeRef' has more than 1 element in PROP_INVADED_BY. Adding its children to 'nodesToPrune' list... (name: \""
+ properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")");
}
// multiple invasion - so it must be a folder
List<ChildAssociationRef> refs = nodeService.getChildAssocsByPropertyValue(currentNodeRef, TransferModel.PROP_INVADED_BY, fromRepositoryId);
for(ChildAssociationRef ref : refs)
{
if(log.isDebugEnabled())
{
log.debug("will need to check child:" + ref);
}
nodesToPrune.push(ref.getChildRef());
}
/**
* Yes we might do something to the children of this node.
*/
if(!foldersToRecalculate.contains(currentNodeRef))
{
if (log.isDebugEnabled())
{
log.debug("Current 'nodeRef' is not in 'foldersToRecalculate' list. Adding it to the list... (name: \"" + properties.get(ContentModel.PROP_NAME)
+ "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\")");
}
foldersToRecalculate.push(currentNodeRef);
}
}
}
else
{
if (log.isDebugEnabled())
{
log.debug("Current \"nodeRef\"'s PROP_INVADED_BY does not contain current 'manifestId' (name: \"" + properties.get(ContentModel.PROP_NAME)
+ "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\")");
}
/**
* Current node has been invaded by another repository
*
* Need to check fromRepositoryId since its children may need to be pruned
*/
getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
{
if(fromRepositoryId.equalsIgnoreCase(initialRepoId))
{
if (log.isDebugEnabled())
{
log.debug("folder is from the transferring repository");
log.debug("Current nodeRef has more than 1 element in PROP_INVADED_BY. Adding its children to 'nodesToPrune' list... (name: \""
+ properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")");
}
// invaded from somewhere else - so it must be a folder
List<ChildAssociationRef> refs = getNodeService().getChildAssocs(currentNodeRef);
for(ChildAssociationRef ref : refs)
{
if(log.isDebugEnabled())
{
log.debug("will need to check child:" + ref);
}
nodesToPrune.push(ref.getChildRef());
/**
* This folder can't be deleted so its invaded flag needs to be re-calculated
*/
if(!foldersToRecalculate.contains(currentNodeRef))
{
if (log.isDebugEnabled())
{
log.debug("Current 'nodeRef' is not in 'foldersToRecalculate' list. Adding it to the list... (name: \""
+ properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")");
}
foldersToRecalculate.push(currentNodeRef);
}
}
}
}
}
}
else
{
// Current node does not contain alien nodes so it can be deleted.
getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
{
if (log.isDebugEnabled())
{
log.debug("Current 'nodeRef' does not have ASPECT_ALIEN (name: \"" + properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \""
+ properties.get(TransferModel.PROP_FROM_REPOSITORY_ID) + "\", manifestId: \"" + fromRepositoryId + "\")");
}
String initialRepoId = (String) getNodeService().getProperty(currentNodeRef, TransferModel.PROP_REPOSITORY_ID);
if(fromRepositoryId.equalsIgnoreCase(initialRepoId))
{
if (log.isDebugEnabled())
{
log.debug("Current \"nodeRef\"'s has PROP_FROM_REPOSITORY_ID equal to current 'manifestId'. Deleting the node... (name: \""
+ properties.get(ContentModel.PROP_NAME) + "\", fromRepositoryId: \"" + properties.get(TransferModel.PROP_FROM_REPOSITORY_ID)
+ "\", manifestId: \"" + fromRepositoryId + "\")");
// we are invaded by a single repository
log.debug("pruned - deleted non alien node:" + currentNodeRef);
}
getNodeService().deleteNode(currentNodeRef);
}
}
}
}
/**
* Now recalculate the "invadedBy" flag for those folders we could not delete.
*/
while(!foldersToRecalculate.isEmpty())
{
NodeRef folderNodeRef = foldersToRecalculate.pop();
log.debug("recalculate invadedBy :" + folderNodeRef);
recalcInvasion(folderNodeRef, fromRepositoryId);
}
/**
* Now ripple up the invaded flag - may be a alien retreat.
*/
log.debug("now ripple upwards");
ChildAssociationRef ripple = startingParent;
while(ripple != null)
{
if(log.isDebugEnabled())
{
log.debug("Checking parent:" + ripple);
}
if(nodeService.hasAspect(ripple.getParentRef(), TransferModel.ASPECT_ALIEN))
{
if(recalcInvasion(ripple.getParentRef(), fromRepositoryId))
{
log.debug("parent is still invaded");
ripple = null;
}
else
{
log.debug("parent is no longer invaded");
ripple = nodeService.getPrimaryParent(ripple.getParentRef());
}
}
else
{
ripple = null;
}
}
log.debug("pruneNode: end");
}
/**
* Is this node invaded ?
* @param nodeRef NodeRef
* @param invader String
* @return true, this node has been invaded by the invader
*/
private boolean isInvaded(NodeRef nodeRef, String invader)
{
List<String>invadedBy = (List<String>)nodeService.getProperty(nodeRef, TransferModel.PROP_INVADED_BY);
if(invadedBy == null)
{
return false;
}
return invadedBy.contains(invader);
}
/**
* Mark the specified node as an alien node, invaded by the specified invader.
* @param newAlien node that has been invaded.
* @param invader the repository id of the invading repo.
*/
private void setAlien(NodeRef newAlien, String invader)
{
// Introduce a Multi-valued property
List<String> invadedBy = (List<String>)nodeService.getProperty(newAlien,
TransferModel.PROP_INVADED_BY);
if(invadedBy == null)
{
invadedBy = new ArrayList<String>(1);
}
if(!invadedBy.contains(invader))
{
invadedBy.add(invader);
}
/**
* Set the invaded by property
*/
nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy);
}
/**
* Determine whether the specified node is invaded by the specified repository
* @param folderNodeRef the node to re-calculate
* @param fromRepositoryId the repository who is transferring.
*
* @return true - still invaded, false, no longer invaded
*/
private boolean recalcInvasion(NodeRef folderNodeRef, String fromRepositoryId)
{
if (log.isTraceEnabled())
{
log.trace("#################");
log.trace("#RECALC INVASION#");
log.trace("#################");
}
List<String> folderInvadedBy = (List<String>)nodeService.getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY);
if (log.isDebugEnabled())
{
log.debug("Node(" + nodeService.getProperty(folderNodeRef, ContentModel.PROP_NAME) + ")" + folderInvadedBy + ": checking '" + fromRepositoryId + "' id...");
}
boolean stillInvaded = false;
boolean hasAlienChild = false;
//TODO need a more efficient query here
List<ChildAssociationRef> refs = nodeService.getChildAssocs(folderNodeRef);
if (log.isDebugEnabled())
{
log.debug("Children count: " + refs.size());
log.debug("Is alien: " + nodeService.hasAspect(folderNodeRef, TransferModel.ASPECT_ALIEN));
}
String parentRepositoryId = (String) nodeService.getProperty(folderNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
for (ChildAssociationRef ref : refs)
{
NodeRef childNode = ref.getChildRef();
if (log.isTraceEnabled())
{
logInvasionHierarchy(folderNodeRef, childNode);
}
Map<QName, Serializable> properties = nodeService.getProperties(childNode);
List<String> childInvadedBy = (List<String>) properties.get(TransferModel.PROP_INVADED_BY);
String childRepositoryId = (String) properties.get(TransferModel.PROP_FROM_REPOSITORY_ID);
hasAlienChild = hasAlienChild || !parentRepositoryId.equalsIgnoreCase(childRepositoryId);
if (!stillInvaded && (null != childInvadedBy) && (childInvadedBy.contains(fromRepositoryId) || fromRepositoryId.equalsIgnoreCase(childRepositoryId)))
{
if (log.isDebugEnabled())
{
log.debug("This child contains current 'fromRepositoryId'. Current folder is still invaded by this repository");
}
stillInvaded = true;
}
}
if (!stillInvaded)
{
if (log.isDebugEnabled())
{
log.debug("Current folder is not invaded by this repository. Updating 'invadedBy' property...");
log.debug("folder is no longer invaded by this repo:" + folderNodeRef);
}
folderInvadedBy.remove(fromRepositoryId);
if (folderInvadedBy.size() > 0)
{
if (log.isDebugEnabled())
{
log.debug("Current folder HAS ANOTHER invasions. Updating the 'invadedBy' property...");
log.debug("still invaded by:" + folderInvadedBy);
}
getNodeService().setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable) folderInvadedBy);
}
else if (!hasAlienChild)
{
if (log.isDebugEnabled())
{
log.debug("no longer alien:" + folderNodeRef);
log.debug("This invasion was the last one for the current folder. Removing aspect 'ALIEN' completely...");
}
getNodeService().removeAspect(folderNodeRef, TransferModel.ASPECT_ALIEN);
}
}
if (log.isTraceEnabled())
{
log.trace("#################");
log.trace("# COMPLETED #");
log.trace("#################");
}
return stillInvaded;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public NodeService getNodeService()
{
return nodeService;
}
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
{
this.behaviourFilter = behaviourFilter;
}
public BehaviourFilter getBehaviourFilter()
{
return behaviourFilter;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
public DictionaryService getDictionaryService()
{
return dictionaryService;
}
public void setDescriptorService(DescriptorService descriptorService)
{
this.descriptorService = descriptorService;
}
public DescriptorService getDescriptorService()
{
return descriptorService;
}
}