ALF-4128 : F99 transfer service (alien invader)

implementation check point - some testing complete.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21637 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mark Rogers
2010-08-05 13:17:56 +00:00
parent 2c97a0e38b
commit ff2b31480d
11 changed files with 2384 additions and 796 deletions

View File

@@ -188,25 +188,41 @@
</aspect>
<aspect name="trx:transferred">
<title>Nodes with this aspect have been transferred from one repository to another
</title>
<title>Transferred Node</title>
<description>Nodes with this aspect have been transferred from one repository to another</description>
<properties>
<property name="trx:repositoryId">
<title>Source RepositoryId</title>
<description>The repository id that this node originates from.</description>
<type>d:text</type>
<mandatory enforced="true">true</mandatory>
</property>
<property name="trx:fromRepositoryId">
<title>The repository that this node was transferred from</title>
<title>From Repository Id</title>
<description>The id of the repository that transferred this node to this repository</description>
<type>d:text</type>
<mandatory enforced="true">true</mandatory>
</property>
</properties>
</aspect>
<aspect name="trx:alien">
<title>Alien Node</title>
<description>Nodes with this aspect are either alien nodes or have been invaded by alien content</description>
<properties>
<property name="trx:alien">
<title>Alien Content</title>
<type>d:boolean</type>
<mandatory enforced="false">false</mandatory>
<default>false</default>
</property>
<property name="trx:invadedBy">
<title>The repositories that have invaded this node</title>
<type>d:text</type>
<mandatory enforced="false">false</mandatory>
<multiple>true</multiple>
<default>false</default>
</property>
</properties>
</aspect>

View File

@@ -54,6 +54,12 @@
<property name="permissionService" ref="PermissionService" />
</bean>
<bean id="alienProcessor" class="org.alfresco.repo.transfer.AlienProcessorImpl"
init-method="init">
<property name="nodeService" ref="NodeService" />
<property name="dictionaryService" ref="DictionaryService" />
<property name="behaviourFilter" ref="policyBehaviourFilter" />
</bean>
<bean id="transferReceiver" class="org.alfresco.repo.transfer.RepoTransferReceiverImpl"
init-method="init">
@@ -63,6 +69,8 @@
<property name="actionService" ref="ActionService" />
<property name="tenantService" ref="tenantService" />
<property name="ruleService" ref="RuleService" />
<property name="descriptorService" ref="DescriptorService" />
<property name="alienProcessor" ref="alienProcessor" />
<property name="transferLockFolderPath">
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}</value>
@@ -107,6 +115,7 @@
<property name="dictionaryService" ref="DictionaryService" />
<property name="permissionService" ref="PermissionService" />
<property name="nodeResolverFactory" ref="transferNodeResolverFactory" />
<property name="alienProcessor" ref="alienProcessor" />
</bean>
<bean id="transferNodeResolverFactory"

View File

@@ -0,0 +1,53 @@
package org.alfresco.repo.transfer;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class groups together the business logic for alien nodes which are
* transferred nodes that contain children from another repository.
* <p>
* Alien nodes cannot be deleted through the transfer service, instead they are
* "pruned"
*
* <p>
* This class owns the aspect trx:alien (TransferModel.ASPECT_ALIEN)
*/
public interface AlienProcessor
{
/**
* Prune the given node of aliens from the specified repositoryId
* @param parentNodeRef the root to prune
* @param fromRepositoryId the repositoryId to prune.
*/
public void pruneNode(NodeRef parentNodeRef, String fromRepositoryId);
/**
* Has the node been invaded by aliens ?
* @param nodeRef the node to check
* @return true the node has been invaded by aliens.
*/
public boolean isAlien(NodeRef nodeRef);
/**
* Called before deleting an alien node.
*
* @param nodeBeingDeleted node about to be deleted
*/
public void beforeDeleteAlien(NodeRef deletedNodeRef);
/**
* Called before creating a child of a transferred node.
*
* When a new node is created as a child of a Transferred or Alien node then
* the new node needs to be marked as an alien.
* <p>
* Then the tree needs to be walked upwards to mark all parent
* transferred nodes as alien.
*
* @param childAssocRef the association ref to the new node
* @param repositoryId - the repositoryId of the system who owns the new node.
*/
public void onCreateChild(ChildAssociationRef childAssocRef, String repositoryId);
}

View File

@@ -0,0 +1,497 @@
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.Stack;
import java.util.Vector;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
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.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 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());
}
public void onCreateChild(ChildAssociationRef childAssocRef, final String repositoryId)
{
log.debug("on create child association to transferred node");
ChildAssociationRef currentAssoc = childAssocRef;
if(!childAssocRef.isPrimary())
{
log.debug("not a primary assoc - do nothing");
return;
}
// TODO Needs to 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;
}
}
NodeRef parentNodeRef = currentAssoc.getParentRef();
NodeRef childNodeRef = currentAssoc.getChildRef();
if(!nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
log.debug("parent was not transferred - 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;
}
}
}
public void beforeDeleteAlien(NodeRef deletedNodeRef)
{
log.debug("on delete node - need to check for transferred node");
List<String>stuff = (List<String>)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY);
Vector<String> exInvaders = new Vector<String>(stuff);
ChildAssociationRef currentAssoc = nodeService.getPrimaryParent(deletedNodeRef);
while(currentAssoc != null && exInvaders != null && exInvaders.size() > 0)
{
NodeRef parentNodeRef = currentAssoc.getParentRef();
NodeRef currentNodeRef = currentAssoc.getChildRef();
/**
* Does the parent have alien invaders ?
*/
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
log.debug("parent node is alien - check siblings");
/**
* 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.
*/
//TODO replace with a more efficient query
List<ChildAssociationRef> refs = nodeService.getChildAssocs(parentNodeRef);
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 boolean isAlien(NodeRef nodeRef)
{
return nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ALIEN);
}
public void pruneNode(NodeRef parentNodeRef, String fromRepositoryId)
{
Stack<NodeRef> nodesToPrune = new Stack<NodeRef>();
Stack<NodeRef> foldersToRecalculate = new Stack<NodeRef>();
nodesToPrune.add(parentNodeRef);
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();
log.debug("pruneNode:" + 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);
if(invadedBy.contains(fromRepositoryId))
{
if(invadedBy.size() == 1)
{
// we are invaded by a single repository which must be fromRepositoryId
log.debug("pruned - deleted node:" + currentNodeRef);
getNodeService().deleteNode(currentNodeRef);
}
else
{
log.debug("folder has multiple invaders");
// multiple invasion - so it must be a folder
//TODO replace with a more efficient query
List<ChildAssociationRef> refs = getNodeService().getChildAssocs(parentNodeRef);
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(ref.getParentRef()))
{
foldersToRecalculate.push(ref.getParentRef());
}
}
}
}
else
{
/**
* 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);
{
String fromRepoId = (String)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
if(fromRepositoryId.equalsIgnoreCase(fromRepoId))
{
log.debug("folder is from the transferring repository");
// 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(ref.getParentRef()))
{
foldersToRecalculate.push(ref.getParentRef());
}
}
}
}
}
}
else
{
// Current node does not contain alien nodes so it can be deleted.
getNodeService().hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
{
String fromRepoId = (String)getNodeService().getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
if(fromRepositoryId.equalsIgnoreCase(fromRepoId))
{
// we are invaded by a single repository
log.debug("pruned - deleted non alien node:" + currentNodeRef);
getNodeService().deleteNode(currentNodeRef);
}
}
}
}
/**
* Now ripple the "invadedBy" flag upwards.
*/
while(!foldersToRecalculate.isEmpty())
{
NodeRef folderNodeRef = foldersToRecalculate.pop();
log.debug("recalculate invadedBy :" + folderNodeRef);
List<String>folderInvadedBy = (List<String>)getNodeService().getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY);
boolean stillInvaded = false;
//TODO need a more efficient query here
List<ChildAssociationRef> refs = getNodeService().getChildAssocs(folderNodeRef);
for(ChildAssociationRef ref : refs)
{
NodeRef childNode = ref.getChildRef();
List<String>childInvadedBy = (List<String>)getNodeService().getProperty(childNode, TransferModel.PROP_INVADED_BY);
if(childInvadedBy.contains(fromRepositoryId))
{
log.debug("folder is still invaded");
stillInvaded = true;
break;
}
}
if(!stillInvaded)
{
List<String> newInvadedBy = new ArrayList<String>(folderInvadedBy);
folderInvadedBy.remove(fromRepositoryId);
getNodeService().setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)newInvadedBy);
}
}
log.debug("pruneNode: end");
}
/**
* Is this node invaded ?
* @param nodeRef
* @param invader
* @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, invadedby the invader.
* @param newAlien
* @param invader
*/
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)
{
nodeService.setProperty(newAlien, TransferModel.PROP_ALIEN, Boolean.TRUE);
invadedBy = new ArrayList<String>(1);
}
invadedBy.add(invader);
/**
* Set the invaded by property
*/
nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy);
// /**
// * Experiment with a residual property
// */
// nodeService.setProperty(newAlien, QName.createQName(TransferModel.TRANSFER_MODEL_1_0_URI,
// "invader" + invader), Boolean.TRUE);
}
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;
}
}

View File

@@ -40,6 +40,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
private DictionaryService dictionaryService;
private PermissionService permissionService;
private CorrespondingNodeResolverFactory nodeResolverFactory;
private AlienProcessor alienProcessor;
/*
* (non-Javadoc)
@@ -57,6 +58,7 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
primaryProcessor.setNodeService(nodeService);
primaryProcessor.setDictionaryService(dictionaryService);
primaryProcessor.setPermissionService(getPermissionService());
primaryProcessor.setAlienProcessor(getAlienProcessor());
processors.add(primaryProcessor);
RepoSecondaryManifestProcessorImpl secondaryProcessor = new RepoSecondaryManifestProcessorImpl(receiver, transferId);
@@ -65,8 +67,8 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
processors.add(secondaryProcessor);
RepoTertiaryManifestProcessorImpl tertiaryProcessor = new RepoTertiaryManifestProcessorImpl(receiver, transferId);
tertiaryProcessor.setNodeResolver(nodeResolver);
tertiaryProcessor.setNodeService(nodeService);
tertiaryProcessor.setAlienProcessor(getAlienProcessor());
processors.add(tertiaryProcessor);
return processors;
@@ -114,7 +116,6 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
RepoRequsiteManifestProcessorImpl processor = new RepoRequsiteManifestProcessorImpl(receiver, transferId, out);
CorrespondingNodeResolver nodeResolver = nodeResolverFactory.getResolver();
processor.setNodeResolver(nodeResolver);
processor.setNodeService(nodeService);
@@ -131,4 +132,14 @@ public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFac
return permissionService;
}
public void setAlienProcessor(AlienProcessor alienProcessor)
{
this.alienProcessor = alienProcessor;
}
public AlienProcessor getAlienProcessor()
{
return alienProcessor;
}
}

View File

@@ -89,6 +89,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
private ContentService contentService;
private DictionaryService dictionaryService;
private CorrespondingNodeResolver nodeResolver;
private AlienProcessor alienProcessor;
// State within this class
/**
@@ -148,18 +149,35 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Does a corresponding node exist in this repo?
if (resolvedNodes.resolvedChild != null)
{
NodeRef exNode = resolvedNodes.resolvedChild;
// Yes, it does. Delete it.
if (log.isDebugEnabled())
{
log.debug("Incoming deleted noderef " + node.getNodeRef()
+ " has been resolved to existing local noderef " + resolvedNodes.resolvedChild
+ " has been resolved to existing local noderef " + exNode
+ " - deleting");
}
logProgress("Deleting local node: " + resolvedNodes.resolvedChild);
nodeService.deleteNode(resolvedNodes.resolvedChild);
//TODO : do we have a business rule that only the "from" repo can delete a node? Yes we do.
if(alienProcessor.isAlien(exNode))
{
logProgress("Pruning local node: " + exNode);
if (log.isDebugEnabled())
{
log.debug("Deleted local node: " + resolvedNodes.resolvedChild);
log.debug("Node to be deleted is alien prune rather than delete: " + exNode);
}
alienProcessor.pruneNode(exNode, header.getRepositoryId());
}
else
{
// TODO Need to restrict to the "from" repo Id.
// Not alien - delete it.
logProgress("Deleting local node: " + exNode);
nodeService.deleteNode(exNode);
if (log.isDebugEnabled())
{
log.debug("Deleted local node: " + exNode);
}
}
}
else
@@ -204,7 +222,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Does a corresponding node exist in this repo?
if (resolvedNodes.resolvedChild != null)
{
// Yes, it does. Update it.
// Yes, the corresponding node does exist. Update it.
if (log.isDebugEnabled())
{
log.debug("Incoming noderef " + node.getNodeRef() + " has been resolved to existing local noderef "
@@ -214,8 +232,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
else
{
// No, there is no corresponding node. Worth just quickly checking
// the archive store...
// No, there is no corresponding node.
NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node.getNodeRef().getId());
if (nodeService.exists(archiveNodeRef))
{
@@ -240,6 +257,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
/**
* Create new node.
*
* @param node
* @param resolvedNodes
@@ -285,13 +303,11 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Split out the content properties and sanitise the others
Map<QName, Serializable> contentProps = processProperties(null, props, null);
// inject transferred property here
if(!contentProps.containsKey(TransferModel.PROP_REPOSITORY_ID))
{
log.debug("injecting repositoryId property");
props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
}
props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
injectTransferred(props);
// Remove the invadedBy property since that is used by the transfer service
// and is local to this repository.
props.remove(TransferModel.PROP_INVADED_BY);
// Do we need to worry about locking this new node ?
if(header.isReadOnly())
@@ -323,7 +339,6 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
nodeService.addAspect(newNode.getChildRef(), aspect, null);
}
ManifestAccessControl acl = node.getAccessControl();
// Apply new ACL to this node
if(acl != null)
@@ -345,6 +360,15 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
}
/**
* are we adding an alien node here? The transfer service has policies disabled
* so have to call the consequence of the policy directly.
*/
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
alienProcessor.onCreateChild(newNode, header.getRepositoryId());
}
// Is the node that we've just added the parent of any orphans that
// we've found earlier?
checkOrphans(newNode.getChildRef());
@@ -359,8 +383,16 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
for (ChildAssociationRef orphan : orphansToClaim)
{
logProgress("Re-parenting previously orphaned node (" + orphan.getChildRef() + ") with found parent " + orphan.getParentRef());
nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(), orphan
ChildAssociationRef newRef = nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(), orphan
.getQName());
/**
* We may be creating an alien node here and the policies are turned off.
*/
if(nodeService.hasAspect(newRef.getParentRef(), TransferModel.ASPECT_TRANSFERRED))
{
alienProcessor.onCreateChild(newRef, header.getRepositoryId());
}
}
// We can now remove the record of these orphans, as their parent
// has been found
@@ -402,9 +434,25 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
|| !currentParent.getTypeQName().equals(parentAssocType)
|| !currentParent.getQName().equals(parentAssocName))
{
/**
* Yes, the parent assoc has changed so we need to move the node
*/
// the parent node may no longer be an alien
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
{
alienProcessor.beforeDeleteAlien(node.getNodeRef());
}
// Yes, we need to move the node
nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName);
ChildAssociationRef newNode = nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName);
logProgress("Moved node " + nodeToUpdate + " to be under parent node " + parentNodeRef);
// We may have created a new alien.
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
alienProcessor.onCreateChild(newNode, header.getRepositoryId());
}
}
log.info("Resolved parent node to " + parentNodeRef);
@@ -418,12 +466,18 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
Map<QName, Serializable> existingProps = nodeService.getProperties(nodeToUpdate);
// inject transferred property here
if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
{
log.debug("injecting repositoryId property");
props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
}
props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
injectTransferred(props);
// if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
// {
// log.debug("injecting repositoryId property");
// props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
// }
// props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
// Remove the invadedBy property since that is used by the transfer service
// and is local to this repository.
props.remove(TransferModel.PROP_INVADED_BY);
// Do we need to worry about locking this updated ?
if(header.isReadOnly())
@@ -437,6 +491,12 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
// Split out the content properties and sanitise the others
Map<QName, Serializable> contentProps = processProperties(nodeToUpdate, props, existingProps);
// If there was already a value for invadedBy then leave it alone rather than replacing it.
if(existingProps.containsKey(TransferModel.PROP_INVADED_BY))
{
props.put(TransferModel.PROP_INVADED_BY, existingProps.get(TransferModel.PROP_INVADED_BY));
}
// Update the non-content properties
nodeService.setProperties(nodeToUpdate, props);
@@ -461,7 +521,13 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
aspectsToRemove.removeAll(suppliedAspects);
/**
* Don't remove the aspects that the transfer service uses itself.
*/
aspectsToRemove.remove(TransferModel.ASPECT_TRANSFERRED);
aspectsToRemove.remove(TransferModel.ASPECT_ALIEN);
suppliedAspects.removeAll(existingAspects);
// Now aspectsToRemove contains the set of aspects to remove
@@ -542,6 +608,7 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
}
}
/**
* This method takes all the received properties and separates them into two parts. The content properties are
* removed from the non-content properties such that the non-content properties remain in the "props" map and the
@@ -798,4 +865,27 @@ public class RepoPrimaryManifestProcessorImpl extends AbstractManifestProcessorB
return permissionService;
}
/**
* inject transferred
*/
private void injectTransferred(Map<QName, Serializable> props)
{
if(!props.containsKey(TransferModel.PROP_REPOSITORY_ID))
{
log.debug("injecting repositoryId property");
props.put(TransferModel.PROP_REPOSITORY_ID, header.getRepositoryId());
}
props.put(TransferModel.PROP_FROM_REPOSITORY_ID, header.getRepositoryId());
}
public void setAlienProcessor(AlienProcessor alienProcessor)
{
this.alienProcessor = alienProcessor;
}
public AlienProcessor getAlienProcessor()
{
return alienProcessor;
}
}

View File

@@ -40,10 +40,10 @@ import org.alfresco.service.namespace.RegexQNamePattern;
*
* The secondary manifest processor performs a second parse of the snapshot file.
*
* It is responsible for linking nodes together, moving them out of the temporary space
* into their final position in the repository. At the point that this processor runs both
* ends (source and target) of the nodes' associations should be available in the receiving
* repository.
* It is responsible for linking nodes together.
*
* At the point that this processor runs both ends (source and target) of the nodes' associations should be
* available in the receiving repository.
*
*/
public class RepoSecondaryManifestProcessorImpl extends AbstractManifestProcessorBase

View File

@@ -19,10 +19,12 @@
package org.alfresco.repo.transfer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
@@ -46,12 +48,11 @@ import org.apache.commons.logging.LogFactory;
* which exist in the target repository that do not exist in the source repository.
*
* If the transfer is not "sync" then this processor does nothing.
*
*/
public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessorBase
{
private NodeService nodeService;
private CorrespondingNodeResolver nodeResolver;
private AlienProcessor alienProcessor;
private static final Log log = LogFactory.getLog(RepoTertiaryManifestProcessorImpl.class);
@@ -83,7 +84,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
protected void processNode(TransferManifestNormalNode node)
{
NodeRef nodeRef = node.getNodeRef();
log.debug("processNode " + nodeRef);
log.debug("processNode : " + nodeRef);
if(isSync)
{
@@ -93,8 +94,11 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
List<NodeRef> expectedChildNodeRefs = new ArrayList<NodeRef>();
for(ChildAssociationRef ref : expectedChildren)
{
if(log.isDebugEnabled())
{
log.debug("expecting child" + ref);
}
expectedChildNodeRefs.add(ref.getChildRef());
}
@@ -103,6 +107,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
if(nodeService.exists(nodeRef))
{
log.debug("destination node exists");
/**
* yes this node exists in the destination.
*/
@@ -126,8 +131,10 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
{
/**
* An unexpected child - if this node has been transferred then
* it needs to be deleted. If it is a local node then we don't
* touch it.
* it needs to be deleted.
*
* another repository then we have to prune the alien children
* rather than deleting it.
*/
log.debug("an unexpected child node:" + child);
if(nodeService.hasAspect(childNodeRef, TransferModel.ASPECT_TRANSFERRED))
@@ -141,7 +148,18 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
if(manifestRepositoryId.equalsIgnoreCase(fromRepositoryId))
{
// Yes the manifest repository Id and the from repository Id match.
if(nodeService.hasAspect(childNodeRef, TransferModel.ASPECT_ALIEN))
{
/**
* This node can't be deleted since it contains alien content
* it needs to be "pruned" of the transferring repo's content instead.
*/
log.debug("node to be deleted contains alien content so needs to be pruned." + childNodeRef);
alienProcessor.pruneNode(childNodeRef, fromRepositoryId);
//pruneNode(childNodeRef, fromRepositoryId);
}
else
{
// Destination node needs to be deleted.
nodeService.deleteNode(childNodeRef);
log.debug("deleted node:" + childNodeRef);
@@ -154,6 +172,7 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
}
}
}
}
protected void processHeader(TransferManifestHeader header)
{
@@ -183,12 +202,168 @@ public class RepoTertiaryManifestProcessorImpl extends AbstractManifestProcessor
this.nodeService = nodeService;
}
/**
* @param nodeResolver
* the nodeResolver to set
*/
public void setNodeResolver(CorrespondingNodeResolver nodeResolver)
// /**
// * Prune out the non aliens from the specified repository
// *
// * Need to walk the tree downwards pruning any aliens for this repository
// *
// * Also any folders remaining need to have their invaded by field rippled upwards since they may no
// * longer be invaded by the specified repository if all the alien children have been pruned.
// *
// * @param nodeRef the node to prune
// * @param fromRepositoryId the repository id of the nodes to prune.
// */
// private void pruneNode(NodeRef parentNodeRef, String fromRepositoryId)
// {
// Stack<NodeRef> nodesToPrune = new Stack<NodeRef>();
// Stack<NodeRef> foldersToRecalculate = new Stack<NodeRef>();
// nodesToPrune.add(parentNodeRef);
//
// 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();
//
// log.debug("pruneNode:" + currentNodeRef);
//
// if(nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_ALIEN))
// {
// // Yes this is an alien node
// List<String>invadedBy = (List<String>)nodeService.getProperty(currentNodeRef, TransferModel.PROP_INVADED_BY);
// if(invadedBy.contains(fromRepositoryId))
// {
// if(invadedBy.size() == 1)
// {
// // we are invaded by a single repository which must be fromRepositoryId
// log.debug("pruned - deleted node:" + currentNodeRef);
// nodeService.deleteNode(currentNodeRef);
// }
// else
// {
// log.debug("folder has multiple invaders");
// // multiple invasion - so it must be a folder
// //TODO replace with a more efficient query
// List<ChildAssociationRef> refs = nodeService.getChildAssocs(parentNodeRef);
// 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(ref.getParentRef()))
// {
// foldersToRecalculate.push(ref.getParentRef());
// }
// }
// }
// }
// else
// {
// /**
// * Current node has been invaded by another repository
// *
// * Need to check fromRepositoryId since its children may need to be pruned
// */
// nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
// {
// String fromRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
// if(fromRepositoryId.equalsIgnoreCase(fromRepoId))
// {
// log.debug("folder is from the transferring repository");
// // invaded from somewhere else - so it must be a folder
// List<ChildAssociationRef> refs = nodeService.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(ref.getParentRef()))
// {
// foldersToRecalculate.push(ref.getParentRef());
// }
// }
// }
// }
// }
// }
// else
// {
// // Current node does not contain alien nodes so it can be deleted.
// nodeService.hasAspect(currentNodeRef, TransferModel.ASPECT_TRANSFERRED);
// {
// String fromRepoId = (String)nodeService.getProperty(currentNodeRef, TransferModel.PROP_FROM_REPOSITORY_ID);
// if(fromRepositoryId.equalsIgnoreCase(fromRepoId))
// {
// // we are invaded by a single repository
// log.debug("pruned - deleted non alien node:" + currentNodeRef);
// nodeService.deleteNode(currentNodeRef);
// }
// }
// }
// }
//
// /**
// * Now ripple the "invadedBy" flag upwards.
// */
//
// while(!foldersToRecalculate.isEmpty())
// {
// NodeRef folderNodeRef = foldersToRecalculate.pop();
//
// log.debug("recalculate invadedBy :" + folderNodeRef);
//
// List<String>folderInvadedBy = (List<String>)nodeService.getProperty(folderNodeRef, TransferModel.PROP_INVADED_BY);
//
// boolean stillInvaded = false;
// //TODO need a more efficient query here
// List<ChildAssociationRef> refs = nodeService.getChildAssocs(folderNodeRef);
// for(ChildAssociationRef ref : refs)
// {
// NodeRef childNode = ref.getChildRef();
// List<String>childInvadedBy = (List<String>)nodeService.getProperty(childNode, TransferModel.PROP_INVADED_BY);
//
// if(childInvadedBy.contains(fromRepositoryId))
// {
// log.debug("folder is still invaded");
// stillInvaded = true;
// break;
// }
// }
//
// if(!stillInvaded)
// {
// List<String> newInvadedBy = new ArrayList<String>(folderInvadedBy);
// folderInvadedBy.remove(fromRepositoryId);
// nodeService.setProperty(folderNodeRef, TransferModel.PROP_INVADED_BY, (Serializable)newInvadedBy);
// }
// }
// log.debug("pruneNode: end");
// }
public void setAlienProcessor(AlienProcessor alienProcessor)
{
this.nodeResolver = nodeResolver;
this.alienProcessor = alienProcessor;
}
public AlienProcessor getAlienProcessor()
{
return alienProcessor;
}
}

View File

@@ -28,10 +28,13 @@ import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.SAXParser;
@@ -67,6 +70,7 @@ import org.alfresco.service.cmr.transfer.TransferException;
import org.alfresco.service.cmr.transfer.TransferProgress;
import org.alfresco.service.cmr.transfer.TransferReceiver;
import org.alfresco.service.cmr.transfer.TransferProgress.Status;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
@@ -158,6 +162,10 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
private TenantService tenantService;
private RuleService ruleService;
private PolicyComponent policyComponent;
private DescriptorService descriptorService;
private AlienProcessor alienProcessor;
//private String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId();
private Map<String,NodeRef> transferLockFolderMap = new ConcurrentHashMap<String, NodeRef>();
private Map<String,NodeRef> transferTempFolderMap = new ConcurrentHashMap<String, NodeRef>();
@@ -176,17 +184,24 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
PropertyCheck.mandatory(this, "inboundTransferRecordsPath", inboundTransferRecordsPath);
PropertyCheck.mandatory(this, "rootStagingDirectory", rootStagingDirectory);
PropertyCheck.mandatory(this, "policyComponent", policyComponent);
PropertyCheck.mandatory(this, "descriptorService", descriptorService);
PropertyCheck.mandatory(this, "alienProcessor", alienProcessor);
// // Register policy behaviours
// this.getPolicyComponent().bindAssociationBehaviour(
// NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
// TransferModel.ASPECT_TRANSFERRED,
// new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT));
//
// this.getPolicyComponent().bindClassBehaviour(
// NodeServicePolicies.BeforeDeleteNodePolicy.QNAME,
// this,
// new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.EVERY_EVENT));
/**
* For every new child of a node with the trx:transferred aspect run this.onCreateChildAssociation
*/
this.getPolicyComponent().bindAssociationBehaviour(
NodeServicePolicies.OnCreateChildAssociationPolicy.QNAME,
TransferModel.ASPECT_TRANSFERRED,
new JavaBehaviour(this, "onCreateChildAssociation", NotificationFrequency.EVERY_EVENT));
/**
* For every node with the trx:alien aspect run this.beforeDeleteNode
*/
this.getPolicyComponent().bindClassBehaviour(
NodeServicePolicies.BeforeDeleteNodePolicy.QNAME,
TransferModel.ASPECT_ALIEN,
new JavaBehaviour(this, "beforeDeleteNode", NotificationFrequency.EVERY_EVENT));
}
@@ -859,14 +874,19 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
}
/**
* @param progressMonitor
* the progressMonitor to set
* Set the ruleService
* @param ruleService
* the ruleService to set
*/
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
/**
* Get the rule service
* @return the rule service
*/
public RuleService getRuleService()
{
return this.ruleService;
@@ -935,10 +955,11 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
}
/**
* When a new node is created as a child of a Transferred node then
* the transferred nodes need to be marked as Alien nodes.
*
* The tree needs to be walked upwards to mark all parent transferred nodes as alien.
* When a new node is created as a child of a Transferred or Alien node then
* the new node needs to be marked as an alien.
* <p>
* Then the tree needs to be walked upwards to mark all parent
* transferred nodes as alien.
*/
public void onCreateChildAssociation(ChildAssociationRef childAssocRef,
boolean isNewNode)
@@ -946,75 +967,273 @@ public class RepoTransferReceiverImpl implements TransferReceiver,
log.debug("on create child association to transferred node");
ChildAssociationRef ref = childAssocRef;
if(childAssocRef.isPrimary())
{
while(ref != null)
{
NodeRef parentNodeRef = ref.getParentRef();
NodeRef childNodeRef = ref.getChildRef();
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
Boolean isAlien = (Boolean)nodeService.getProperty(parentNodeRef, TransferModel.PROP_ALIEN);
if (!isAlien)
{
log.debug("setting node as alien:" + parentNodeRef);
nodeService.setProperty(parentNodeRef, TransferModel.PROP_ALIEN, Boolean.TRUE);
ref = nodeService.getPrimaryParent(parentNodeRef);
}
else
{
log.debug("parent node is already alien");
ref = null;
}
}
else
{
log.debug("parent is not a transferred node");
ref = null;
}
}
}
final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId();
alienProcessor.onCreateChild(childAssocRef, localRepositoryId);
//
// ChildAssociationRef currentAssoc = childAssocRef;
//
// final String localRepositoryId = descriptorService.getCurrentRepositoryDescriptor().getId();
//
// // TODO Needs to check assoc is a cm:contains or subtype
// if(childAssocRef.isPrimary())
// {
// NodeRef parentNodeRef = currentAssoc.getParentRef();
// NodeRef childNodeRef = currentAssoc.getChildRef();
//
// /**
// * Make the new child node ref an alien node
// */
// setAlien(childNodeRef, localRepositoryId);
//
// /**
// * 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, localRepositoryId))
// {
// if(log.isDebugEnabled())
// {
// log.debug("alien invades parent node:" + parentNodeRef + ", repositoryId:" + localRepositoryId);
// }
//
// 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
// {
// behaviourFilter.disableBehaviour(newAlien, ContentModel.ASPECT_AUDITABLE);
// behaviourFilter.disableBehaviour(newAlien, ContentModel.ASPECT_LOCKABLE);
// setAlien(newAlien, localRepositoryId);
// 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;
// }
// }
// }
}
/**
* When an old node is deleted that is a child of a transferred node the tree may need to be walked to
* mark parent folder as non alien.
* When an alien node is deleted the it may be the last alien invader
* <p>
* Walk the tree checking the invasion status!
*/
public void beforeDeleteNode(NodeRef nodeRef)
public void beforeDeleteNode(NodeRef deletedNodeRef)
{
log.debug("on delete node - need to check for transferred node");
ChildAssociationRef ref = nodeService.getPrimaryParent(nodeRef);
while(ref != null)
{
NodeRef parentNodeRef = ref.getParentRef();
/**
* Was the parent node transferred ?
*/
if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_TRANSFERRED))
{
log.debug("parent node was transferred - check siblings");
/**
* Check the siblings of this node to see whether there are any other alien nodes.
*/
// nodeService.getChildAssocs(parentNodeRef);
// BUGBUG Code not complete
ref = null;
alienProcessor.beforeDeleteAlien(deletedNodeRef);
//
// List<String>stuff = (List<String>)nodeService.getProperty(deletedNodeRef, TransferModel.PROP_INVADED_BY);
//
// Vector<String> exInvaders = new Vector<String>(stuff);
//
// ChildAssociationRef currentAssoc = nodeService.getPrimaryParent(deletedNodeRef);
//
// while(currentAssoc != null && exInvaders != null && exInvaders.size() > 0)
// {
// NodeRef parentNodeRef = currentAssoc.getParentRef();
// NodeRef currentNodeRef = currentAssoc.getChildRef();
//
// /**
// * Does the parent have alien invaders ?
// */
// if(nodeService.hasAspect(parentNodeRef, TransferModel.ASPECT_ALIEN))
// {
// log.debug("parent node is alien - check siblings");
//
// /**
// * 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.
// */
// //TODO replace with a more efficient query
// List<ChildAssociationRef> refs = nodeService.getChildAssocs(parentNodeRef);
//
// 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 no is no longer alien");
// 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
}
else
// /**
// * Is this node invaded ?
// * @param nodeRef
// * @param invader
// * @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, invadedby the invader.
// * @param newAlien
// * @param invader
// */
// 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)
// {
// nodeService.setProperty(newAlien, TransferModel.PROP_ALIEN, Boolean.TRUE);
// invadedBy = new ArrayList<String>(1);
// }
// invadedBy.add(invader);
//
// /**
// * Set the invaded by property
// */
// nodeService.setProperty(newAlien, TransferModel.PROP_INVADED_BY, (Serializable) invadedBy);
//
// /**
// * Experiment with a residual property
// */
// nodeService.setProperty(newAlien, QName.createQName(TransferModel.TRANSFER_MODEL_1_0_URI,
// "invader" + invader), Boolean.TRUE);
//
// }
public void setDescriptorService(DescriptorService descriptorService)
{
log.debug("parent is not a transferred node");
ref = null;
this.descriptorService = descriptorService;
}
public DescriptorService getDescriptorService()
{
return descriptorService;
}
public void setAlienProcessor(AlienProcessor alienProcessor)
{
this.alienProcessor = alienProcessor;
}
public AlienProcessor getAlienProcessor()
{
return alienProcessor;
}
}

View File

@@ -39,7 +39,14 @@ public interface TransferModel
static final QName ASPECT_TRANSFERRED = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferred");
static final QName PROP_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "repositoryId");
static final QName PROP_FROM_REPOSITORY_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "fromRepositoryId");
/**
* Aspect : alien
*/
static final QName ASPECT_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien");
static final QName PROP_INVADED_BY = QName.createQName(TRANSFER_MODEL_1_0_URI, "invadedBy");
static final QName PROP_ALIEN = QName.createQName(TRANSFER_MODEL_1_0_URI, "alien");
/*
* Type : Transfer Group
*/
@@ -73,7 +80,6 @@ public interface TransferModel
static final QName PROP_TRANSFER_STATUS = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferStatus");
static final QName PROP_TRANSFER_ERROR = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferError");
/*
* Type : Transfer report
*/