Search in sources :

Example 1 with NodeExistsException

use of org.alfresco.repo.domain.node.NodeExistsException in project alfresco-repository by Alfresco.

the class DbNodeServiceImpl method archiveHierarchyImpl.

/**
 * Archive (direct copy) a node hierarchy
 *
 * @param walker                the node hierarchy to archive
 * @param archiveStoreRef StoreRef
 */
private void archiveHierarchyImpl(NodeHierarchyWalker walker, StoreRef archiveStoreRef) {
    // Start with the node we are archiving to
    Pair<Long, NodeRef> archiveStoreRootNodePair = nodeDAO.getRootNode(archiveStoreRef);
    // Work through the hierarchy from the top down and archive all the nodes
    boolean firstNode = true;
    Map<Long, Pair<Long, NodeRef>> archiveRecord = new HashMap<Long, Pair<Long, NodeRef>>(walker.getNodes(false).size() * 2);
    for (VisitedNode node : walker.getNodes(false)) {
        // Get node metadata
        Map<QName, Serializable> archiveProperties = nodeDAO.getNodeProperties(node.id);
        Set<QName> archiveAspects = nodeDAO.getNodeAspects(node.id);
        // The first node gets special treatment as it contains the archival details
        ChildAssociationRef archivePrimaryParentAssocRef = null;
        final Pair<Long, NodeRef> archiveParentNodePair;
        if (firstNode) {
            // Attach top-level archival details
            ChildAssociationRef primaryParentAssocRef = node.primaryParentAssocPair.getSecond();
            archiveAspects.add(ContentModel.ASPECT_ARCHIVED);
            archiveProperties.put(ContentModel.PROP_ARCHIVED_BY, AuthenticationUtil.getFullyAuthenticatedUser());
            archiveProperties.put(ContentModel.PROP_ARCHIVED_DATE, new Date());
            archiveProperties.put(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC, primaryParentAssocRef);
            Serializable originalOwner = archiveProperties.get(ContentModel.PROP_OWNER);
            archiveProperties.put(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER, originalOwner != null ? originalOwner : OwnableService.NO_OWNER);
            // change the node ownership
            archiveAspects.add(ContentModel.ASPECT_OWNABLE);
            archiveProperties.put(ContentModel.PROP_OWNER, AuthenticationUtil.getFullyAuthenticatedUser());
            // Create new primary association
            archivePrimaryParentAssocRef = new ChildAssociationRef(ContentModel.ASSOC_CHILDREN, archiveStoreRootNodePair.getSecond(), NodeArchiveService.QNAME_ARCHIVED_ITEM, new NodeRef(archiveStoreRef, node.nodeRef.getId()), true, -1);
            archiveParentNodePair = archiveStoreRootNodePair;
        } else {
            ChildAssociationRef primaryParentAssocRef = node.primaryParentAssocPair.getSecond();
            NodeRef parentNodeRef = primaryParentAssocRef.getParentRef();
            // Look it up
            VisitedNode parentNode = walker.getNode(parentNodeRef);
            if (parentNode == null) {
                throw new IllegalStateException("Expected that a child has a visited primary parent: " + primaryParentAssocRef);
            }
            // This needs to have been mapped to a new parent
            archiveParentNodePair = archiveRecord.get(parentNode.id);
            if (archiveParentNodePair == null) {
                throw new IllegalStateException("Expected to have archived primary parent: " + primaryParentAssocRef);
            }
            // Build the primary association details
            archivePrimaryParentAssocRef = new ChildAssociationRef(primaryParentAssocRef.getTypeQName(), archiveParentNodePair.getSecond(), primaryParentAssocRef.getQName(), new NodeRef(archiveStoreRef, node.nodeRef.getId()), true, primaryParentAssocRef.getNthSibling());
        }
        // Invoke behaviours
        invokeBeforeCreateNode(archivePrimaryParentAssocRef.getParentRef(), archivePrimaryParentAssocRef.getTypeQName(), archivePrimaryParentAssocRef.getQName(), node.nodeType);
        // Create a new node
        boolean attempted = false;
        Node archiveNode = null;
        while (true) {
            try {
                ChildAssocEntity archiveChildAssocEntity = nodeDAO.newNode(archiveParentNodePair.getFirst(), archivePrimaryParentAssocRef.getTypeQName(), archivePrimaryParentAssocRef.getQName(), archiveStoreRef, node.nodeRef.getId(), node.nodeType, (Locale) archiveProperties.get(ContentModel.PROP_LOCALE), (String) archiveProperties.get(ContentModel.PROP_NAME), archiveProperties);
                archiveNode = archiveChildAssocEntity.getChildNode();
                // Store the archive mapping for this node
                archiveRecord.put(node.id, archiveNode.getNodePair());
                break;
            } catch (NodeExistsException e) {
                if (!attempted) {
                    // There is a conflict, so delete the currently-archived node
                    NodeRef conflictingNodeRef = e.getNodePair().getSecond();
                    deleteNode(conflictingNodeRef);
                    attempted = true;
                } else {
                    throw e;
                }
            }
        }
        // Carry any explicit permissions over to the new node
        Set<AccessPermission> originalNodePermissions = permissionService.getAllSetPermissions(node.nodeRef);
        for (AccessPermission originalPermission : originalNodePermissions) {
            if (originalPermission.isInherited()) {
                // Ignore inherited permissions
                continue;
            }
            NodeRef archiveNodeRef = archiveNode.getNodeRef();
            permissionService.setPermission(archiveNodeRef, originalPermission.getAuthority(), originalPermission.getPermission(), originalPermission.getAccessStatus() == AccessStatus.ALLOWED);
        }
        // Check if it inherits permissions or not
        if (!permissionService.getInheritParentPermissions(node.nodeRef)) {
            permissionService.setInheritParentPermissions(archiveNode.getNodeRef(), false);
        }
        // Add properties and aspects
        Long archiveNodeId = archiveNode.getId();
        NodeRef archiveNodeRef = archiveNode.getNodeRef();
        nodeDAO.addNodeAspects(archiveNodeId, archiveAspects);
        nodeDAO.addNodeProperties(archiveNodeId, archiveProperties);
        // username is linked to the document
        if (firstNode) {
            // Attach archiveRoot aspect to root
            // TODO: In time, this can be moved into a patch
            Long archiveStoreRootNodeId = archiveStoreRootNodePair.getFirst();
            NodeRef archiveStoreRootNodeRef = archiveStoreRootNodePair.getSecond();
            if (!nodeDAO.hasNodeAspect(archiveStoreRootNodeId, ContentModel.ASPECT_ARCHIVE_ROOT)) {
                addAspect(archiveStoreRootNodeRef, ContentModel.ASPECT_ARCHIVE_ROOT, null);
            }
            // Ensure that the user has a folder for archival
            String username = AuthenticationUtil.getFullyAuthenticatedUser();
            if (username == null) {
                username = AuthenticationUtil.getAdminUserName();
            }
            Pair<Long, ChildAssociationRef> userArchiveAssocPair = nodeDAO.getChildAssoc(archiveStoreRootNodeId, ContentModel.ASSOC_ARCHIVE_USER_LINK, username);
            NodeRef userArchiveNodeRef = null;
            if (userArchiveAssocPair == null) {
                // User has no node entry.  Create a new one.
                QName archiveUserAssocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(username));
                Map<QName, Serializable> userArchiveNodeProps = Collections.singletonMap(ContentModel.PROP_NAME, (Serializable) username);
                userArchiveNodeRef = createNode(archiveStoreRootNodeRef, ContentModel.ASSOC_ARCHIVE_USER_LINK, archiveUserAssocQName, ContentModel.TYPE_ARCHIVE_USER, userArchiveNodeProps).getChildRef();
            } else {
                userArchiveNodeRef = userArchiveAssocPair.getSecond().getChildRef();
            }
            // Link user node to archived item via secondary child association
            String archiveNodeName = (String) archiveProperties.get(ContentModel.PROP_NAME);
            if (archiveNodeName == null) {
                archiveNodeName = archiveNodeRef.getId();
            }
            QName archiveAssocQName = QName.createQNameWithValidLocalName(NamespaceService.SYSTEM_MODEL_1_0_URI, archiveNodeName);
            addChild(userArchiveNodeRef, archiveNodeRef, ContentModel.ASSOC_ARCHIVED_LINK, archiveAssocQName);
        }
        // Invoke behaviours
        invokeOnCreateNode(archivePrimaryParentAssocRef);
        firstNode = false;
    }
}
Also used : Serializable(java.io.Serializable) HashMap(java.util.HashMap) QName(org.alfresco.service.namespace.QName) NodeExistsException(org.alfresco.repo.domain.node.NodeExistsException) VisitedNode(org.alfresco.repo.node.db.NodeHierarchyWalker.VisitedNode) Node(org.alfresco.repo.domain.node.Node) AccessPermission(org.alfresco.service.cmr.security.AccessPermission) ChildAssociationRef(org.alfresco.service.cmr.repository.ChildAssociationRef) Date(java.util.Date) NodeRef(org.alfresco.service.cmr.repository.NodeRef) ChildAssocEntity(org.alfresco.repo.domain.node.ChildAssocEntity) VisitedNode(org.alfresco.repo.node.db.NodeHierarchyWalker.VisitedNode) Pair(org.alfresco.util.Pair)

Example 2 with NodeExistsException

use of org.alfresco.repo.domain.node.NodeExistsException in project alfresco-repository by Alfresco.

the class DbNodeServiceImpl method moveNode.

/**
 * Move Node
 *
 * Drops the old primary association and creates a new one
 */
@Extend(traitAPI = NodeServiceTrait.class, extensionAPI = NodeServiceExtension.class)
public ChildAssociationRef moveNode(NodeRef nodeToMoveRef, NodeRef newParentRef, QName assocTypeQName, QName assocQName) {
    // The node(s) involved may not be pending deletion
    checkPendingDelete(nodeToMoveRef);
    checkPendingDelete(newParentRef);
    Pair<Long, NodeRef> nodeToMovePair = getNodePairNotNull(nodeToMoveRef);
    Pair<Long, NodeRef> parentNodePair = getNodePairNotNull(newParentRef);
    Long nodeToMoveId = nodeToMovePair.getFirst();
    NodeRef oldNodeToMoveRef = nodeToMovePair.getSecond();
    Long parentNodeId = parentNodePair.getFirst();
    NodeRef parentNodeRef = parentNodePair.getSecond();
    StoreRef oldStoreRef = oldNodeToMoveRef.getStoreRef();
    StoreRef newStoreRef = parentNodeRef.getStoreRef();
    List<ChildAssociationRef> nodesToRestoreAssociationsFor = new ArrayList<ChildAssociationRef>();
    // Get the primary parent association
    Pair<Long, ChildAssociationRef> oldParentAssocPair = nodeDAO.getPrimaryParentAssoc(nodeToMoveId);
    if (oldParentAssocPair == null) {
        // The node doesn't have parent.  Moving it is not possible.
        throw new IllegalArgumentException("Node " + nodeToMoveId + " doesn't have a parent.  Use 'addChild' instead of move.");
    }
    ChildAssociationRef oldParentAssocRef = oldParentAssocPair.getSecond();
    boolean movingStore = !oldStoreRef.equals(newStoreRef);
    if (movingStore) {
        // Recursively find primary children of the node to move
        // TODO: Use NodeHierarchyWalker
        List<ChildAssociationRef> childAssocs = new LinkedList<ChildAssociationRef>();
        Map<NodeRef, Long> oldChildNodeIds = new HashMap<NodeRef, Long>(97);
        findNodeChildrenToMove(nodeToMoveId, newStoreRef, childAssocs, oldChildNodeIds);
        // Invoke "Before Delete" policy behaviour
        invokeBeforeDeleteNode(nodeToMoveRef);
        // do the same to the children, preserving parents, types and qnames
        for (ChildAssociationRef oldChildAssoc : childAssocs) {
            // Fire before delete policy. Before create policy needs the new parent ref to exist, so will be fired later
            invokeBeforeDeleteNode(oldChildAssoc.getChildRef());
        }
        // Now do the moving and remaining policy firing
        Map<NodeRef, Pair<Long, NodeRef>> movedNodePairs = new HashMap<NodeRef, Pair<Long, NodeRef>>(childAssocs.size() * 2 + 2);
        QName childNodeTypeQName = nodeDAO.getNodeType(nodeToMoveId);
        Set<QName> childNodeAspectQNames = nodeDAO.getNodeAspects(nodeToMoveId);
        // Fire before create immediately before moving with all parents in place
        invokeBeforeCreateNode(newParentRef, assocTypeQName, assocQName, childNodeTypeQName);
        // Move node under the new parent
        Pair<Pair<Long, ChildAssociationRef>, Pair<Long, NodeRef>> moveNodeResult = nodeDAO.moveNode(nodeToMoveId, parentNodeId, assocTypeQName, assocQName);
        Pair<Long, ChildAssociationRef> newParentAssocPair = moveNodeResult.getFirst();
        movedNodePairs.put(nodeToMoveRef, moveNodeResult.getSecond());
        ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond();
        // Propagate timestamps
        propagateTimeStamps(oldParentAssocRef);
        propagateTimeStamps(newParentAssocRef);
        // The Node changes NodeRefs, so this is really the deletion of the old node and creation
        // of a node in a new store as far as the clients are concerned.
        invokeOnDeleteNode(oldParentAssocRef, childNodeTypeQName, childNodeAspectQNames, true);
        invokeOnCreateNode(newParentAssocRef);
        // do the same to the children, preserving parents, types and qnames
        for (ChildAssociationRef oldChildAssoc : childAssocs) {
            NodeRef oldChildNodeRef = oldChildAssoc.getChildRef();
            Long oldChildNodeId = oldChildNodeIds.get(oldChildNodeRef);
            NodeRef oldParentNodeRef = oldChildAssoc.getParentRef();
            Pair<Long, NodeRef> newParentNodePair = movedNodePairs.get(oldParentNodeRef);
            Long newParentNodeId = newParentNodePair.getFirst();
            childNodeTypeQName = nodeDAO.getNodeType(oldChildNodeId);
            childNodeAspectQNames = nodeDAO.getNodeAspects(oldChildNodeId);
            // Now that the new parent ref exists, invoke the before create policy
            invokeBeforeCreateNode(newParentNodePair.getSecond(), oldChildAssoc.getTypeQName(), oldChildAssoc.getQName(), childNodeTypeQName);
            // Move the node as this gives back the primary parent association
            try {
                moveNodeResult = nodeDAO.moveNode(oldChildNodeId, newParentNodeId, null, null);
            } catch (NodeExistsException e) {
                deleteNode(e.getNodePair().getSecond());
                moveNodeResult = nodeDAO.moveNode(oldChildNodeId, newParentNodeId, null, null);
            }
            // Move the node as this gives back the primary parent association
            newParentAssocPair = moveNodeResult.getFirst();
            movedNodePairs.put(oldChildNodeRef, moveNodeResult.getSecond());
            ChildAssociationRef newChildAssoc = newParentAssocPair.getSecond();
            // Propagate timestamps
            propagateTimeStamps(newChildAssoc);
            // Fire node policies.  This ensures that each node in the hierarchy gets a notification fired.
            invokeOnDeleteNode(oldChildAssoc, childNodeTypeQName, childNodeAspectQNames, true);
            invokeOnCreateNode(newChildAssoc);
            // to be already moved when create association between nodes
            if (hasAspect(newChildAssoc.getChildRef(), ContentModel.ASPECT_ARCHIVE_LOCKABLE)) {
                nodesToRestoreAssociationsFor.add(newChildAssoc);
            }
        }
        // invoke onRestoreNode for working copy nodes in order to restore original lock
        for (ChildAssociationRef childAssoc : nodesToRestoreAssociationsFor) {
            invokeOnRestoreNode(childAssoc);
        }
        return newParentAssocRef;
    } else {
        invokeBeforeMoveNode(oldParentAssocRef, newParentRef);
        invokeBeforeDeleteChildAssociation(oldParentAssocRef);
        // Move node under the new parent
        Pair<Pair<Long, ChildAssociationRef>, Pair<Long, NodeRef>> moveNodeResult = nodeDAO.moveNode(nodeToMoveId, parentNodeId, assocTypeQName, assocQName);
        Pair<Long, ChildAssociationRef> newParentAssocPair = moveNodeResult.getFirst();
        ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond();
        // Propagate timestamps (watch out for moves within the same folder)
        if (!oldParentAssocRef.getParentRef().equals(newParentAssocRef.getParentRef())) {
            propagateTimeStamps(oldParentAssocRef);
            propagateTimeStamps(newParentAssocRef);
        } else {
            // Propagate timestamps for rename case, see ALF-10884
            propagateTimeStamps(newParentAssocRef);
        }
        invokeOnCreateChildAssociation(newParentAssocRef, false);
        invokeOnDeleteChildAssociation(oldParentAssocRef);
        invokeOnMoveNode(oldParentAssocRef, newParentAssocRef);
        // Done
        return newParentAssocRef;
    }
}
Also used : StoreRef(org.alfresco.service.cmr.repository.StoreRef) HashMap(java.util.HashMap) QName(org.alfresco.service.namespace.QName) NodeExistsException(org.alfresco.repo.domain.node.NodeExistsException) ArrayList(java.util.ArrayList) ChildAssociationRef(org.alfresco.service.cmr.repository.ChildAssociationRef) LinkedList(java.util.LinkedList) NodeRef(org.alfresco.service.cmr.repository.NodeRef) Pair(org.alfresco.util.Pair) Extend(org.alfresco.traitextender.Extend)

Aggregations

HashMap (java.util.HashMap)2 NodeExistsException (org.alfresco.repo.domain.node.NodeExistsException)2 ChildAssociationRef (org.alfresco.service.cmr.repository.ChildAssociationRef)2 NodeRef (org.alfresco.service.cmr.repository.NodeRef)2 QName (org.alfresco.service.namespace.QName)2 Pair (org.alfresco.util.Pair)2 Serializable (java.io.Serializable)1 ArrayList (java.util.ArrayList)1 Date (java.util.Date)1 LinkedList (java.util.LinkedList)1 ChildAssocEntity (org.alfresco.repo.domain.node.ChildAssocEntity)1 Node (org.alfresco.repo.domain.node.Node)1 VisitedNode (org.alfresco.repo.node.db.NodeHierarchyWalker.VisitedNode)1 StoreRef (org.alfresco.service.cmr.repository.StoreRef)1 AccessPermission (org.alfresco.service.cmr.security.AccessPermission)1 Extend (org.alfresco.traitextender.Extend)1