()
                            {
                                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
     * 
     * Steps down the tree retreating from all the invaded nodes.
     * 
     * The retreat will stop is there is a "sub-invasion".
     * 
   
     * @param nodeRef the top of the tree
     * @param fromRepositoryId the repository that is retreating.
     */
    private void retreatDownwards(NodeRef nodeRef, String fromRepositoryId)
    {
        Stack nodesToRetreat = new Stack();
        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
                ListinvadedBy = (List)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 refs = getNodeService().getChildAssocs(currentNodeRef);
                    List 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 nodesToPrune = new Stack();
        nodesToPrune.add(nodeToPrune);
        
        ChildAssociationRef startingParent = nodeService.getPrimaryParent(nodeToPrune);
        
        Stack foldersToRecalculate = new Stack();
        /**
         * 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 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 invadedBy = (List)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 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 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)
    {
        ListinvadedBy = (List)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 invadedBy = (List)nodeService.getProperty(newAlien, 
                TransferModel.PROP_INVADED_BY);
        
        if(invadedBy == null)
        {
            invadedBy = new ArrayList(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 folderInvadedBy = (List)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 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 properties = nodeService.getProperties(childNode);
            List childInvadedBy = (List) 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;
    }
}