diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index bdb4da9e88..428cfadad5 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -26,6 +26,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -2560,7 +2561,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair parentNodePair = getNodePairNotNull(newParentRef); Long nodeToMoveId = nodeToMovePair.getFirst(); - QName nodeToMoveTypeQName = nodeDAO.getNodeType(nodeToMoveId); NodeRef oldNodeToMoveRef = nodeToMovePair.getSecond(); Long parentNodeId = parentNodePair.getFirst(); NodeRef parentNodeRef = parentNodePair.getSecond(); @@ -2576,64 +2576,123 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } ChildAssociationRef oldParentAssocRef = oldParentAssocPair.getSecond(); - // Get the aspects for later use - Set nodeToMoveAspectQNames = nodeDAO.getNodeAspects(nodeToMoveId); - boolean movingStore = !oldStoreRef.equals(newStoreRef); - - // Invoke "Before"policy behaviour - if (movingStore) - { - invokeBeforeDeleteNode(nodeToMoveRef); - invokeBeforeCreateNode(newParentRef, assocTypeQName, assocQName, nodeToMoveTypeQName); - } - else - { - invokeBeforeMoveNode(oldParentAssocRef, newParentRef); - invokeBeforeDeleteChildAssociation(oldParentAssocRef); - } - - // Move node under the new parent - Pair, Pair> moveNodeResult = nodeDAO.moveNode( - nodeToMoveId, - parentNodeId, - assocTypeQName, - assocQName); - Pair newParentAssocPair = moveNodeResult.getFirst(); - Pair newNodeToMovePair = moveNodeResult.getSecond(); - ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); - // Handle indexing differently if it is a store move if (movingStore) { - // The association existed before and the node is moving to a new store + // Recursively find primary children of the node to move + // TODO: Use NodeHierarchyWalker + List childAssocs = new LinkedList(); + Map oldChildNodeIds = new HashMap(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> movedNodePairs = new HashMap>(childAssocs.size() * 2 + 2); + QName childNodeTypeQName = nodeDAO.getNodeType(nodeToMoveId); + Set 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> moveNodeResult = nodeDAO.moveNode( + nodeToMoveId, + parentNodeId, + assocTypeQName, + assocQName); + Pair newParentAssocPair = moveNodeResult.getFirst(); + movedNodePairs.put(nodeToMoveRef, moveNodeResult.getSecond()); + ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); + + // Index nodeIndexer.indexDeleteNode(oldParentAssocRef); nodeIndexer.indexCreateNode(newParentAssocRef); - } - else - { - // The node is in the same store and is just having it's child association modified - nodeIndexer.indexUpdateChildAssociation(oldParentAssocRef, newParentAssocRef); - } - - // Call behaviours - // TODO: Use NodeHierarchyWalker - if (movingStore) - { + // 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, nodeToMoveTypeQName, nodeToMoveAspectQNames, true); + invokeOnDeleteNode(oldParentAssocRef, childNodeTypeQName, childNodeAspectQNames, true); invokeOnCreateNode(newParentAssocRef); - // Pull children to the new store - pullNodeChildrenToSameStore(newNodeToMovePair); + // 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 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(); + + // Index + nodeIndexer.indexDeleteNode(oldChildAssoc); + nodeIndexer.indexCreateNode(newChildAssoc); + + // 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); + } + + return newParentAssocRef; } else { + invokeBeforeMoveNode(oldParentAssocRef, newParentRef); + + invokeBeforeDeleteChildAssociation(oldParentAssocRef); + + // Move node under the new parent + Pair, Pair> moveNodeResult = nodeDAO.moveNode( + nodeToMoveId, + parentNodeId, + assocTypeQName, + assocQName); + Pair newParentAssocPair = moveNodeResult.getFirst(); + ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); + + // The node is in the same store and is just having its child association modified + nodeIndexer.indexUpdateChildAssociation(oldParentAssocRef, newParentAssocRef); + // Propagate timestamps (watch out for moves within the same folder) if (!oldParentAssocRef.getParentRef().equals(newParentAssocRef.getParentRef())) { @@ -2648,22 +2707,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeOnCreateChildAssociation(newParentAssocRef, false); invokeOnDeleteChildAssociation(oldParentAssocRef); - invokeOnMoveNode(oldParentAssocRef, newParentAssocRef); + invokeOnMoveNode(oldParentAssocRef, newParentAssocRef); + + // Done + return newParentAssocRef; } - - // Done - return newParentAssocRef; } - /** - * This process is less invasive than the move method as the child associations - * do not need to be remade. - */ - private void pullNodeChildrenToSameStore(Pair nodePair) + private void findNodeChildrenToMove(Long nodeId, final StoreRef storeRef, + final List childAssocsToMove, final Map nodeIds) { - Long nodeId = nodePair.getFirst(); // Get the node's children, but only one's that aren't in the same store - final List> childNodePairs = new ArrayList>(5); + final List childAssocs = new LinkedList(); NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean preLoadNodes() @@ -2683,8 +2738,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair childNodePair ) { - // Add it - childNodePairs.add(childNodePair); + // Add it if it's not in the target store + NodeRef childNodeRef = childNodePair.getSecond(); + if (!childNodeRef.getStoreRef().equals(storeRef)) + { + childAssocs.add(childAssocPair.getSecond()); + nodeIds.put(childNodeRef, childNodePair.getFirst()); + } // More results return true; } @@ -2693,58 +2753,23 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { } }; - // We only need to move child nodes that are not already in the same store - nodeDAO.getChildAssocs(nodeId, null, null, null, Boolean.TRUE, Boolean.FALSE, callback); + // We need to get all primary children and do the store filtering ourselves + nodeDAO.getChildAssocs(nodeId, null, null, null, Boolean.TRUE, null, callback); + // Each child must be moved to the same store as the parent - for (Pair oldChildNodePair : childNodePairs) + for (ChildAssociationRef oldChildAssoc : childAssocs) { - Long childNodeId = oldChildNodePair.getFirst(); - NodeRef childNodeRef = oldChildNodePair.getSecond(); + NodeRef childNodeRef = oldChildAssoc.getChildRef(); + Long childNodeId = nodeIds.get(childNodeRef); NodeRef.Status childNodeStatus = nodeDAO.getNodeRefStatus(childNodeRef); if (childNodeStatus == null || childNodeStatus.isDeleted()) { // Node has already been deleted. continue; } - - QName childNodeTypeQName = nodeDAO.getNodeType(childNodeId); - Set childNodeAspectQNames = nodeDAO.getNodeAspects(childNodeId); - Pair oldParentAssocPair = nodeDAO.getPrimaryParentAssoc(childNodeId); - ChildAssociationRef oldParentAssocRef = oldParentAssocPair.getSecond(); - - // Fire node policies. This ensures that each node in the hierarchy gets a notification fired. - invokeBeforeDeleteNode(childNodeRef); - invokeBeforeCreateNode( - oldParentAssocPair.getSecond().getParentRef(), - oldParentAssocPair.getSecond().getTypeQName(), - oldParentAssocPair.getSecond().getQName(), - childNodeTypeQName); - // Move the node as this gives back the primary parent association - Pair, Pair> moveResult; - try - { - moveResult = nodeDAO.moveNode(childNodeId, nodeId, null,null); - } - catch (NodeExistsException e) - { - deleteNode(e.getNodePair().getSecond()); - moveResult = nodeDAO.moveNode(childNodeId, nodeId, null,null); - } - // Move the node as this gives back the primary parent association - Pair newParentAssocPair = moveResult.getFirst(); - Pair newChildNodePair = moveResult.getSecond(); - ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); - // Index - nodeIndexer.indexDeleteNode(oldParentAssocPair.getSecond()); - nodeIndexer.indexCreateNode(newParentAssocPair.getSecond()); - // Propagate timestamps - propagateTimeStamps(oldParentAssocRef); - propagateTimeStamps(newParentAssocRef); - // Fire node policies. This ensures that each node in the hierarchy gets a notification fired. - invokeOnDeleteNode(oldParentAssocRef, childNodeTypeQName, childNodeAspectQNames, true); - invokeOnCreateNode(newParentAssocRef); + childAssocsToMove.add(oldChildAssoc); // Cascade - pullNodeChildrenToSameStore(newChildNodePair); + findNodeChildrenToMove(childNodeId, storeRef, childAssocsToMove, nodeIds); } } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java index f94efb87fa..89a3e2ce3e 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnContentUpdateRuleTrigger.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -104,7 +104,7 @@ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase { // Note: Don't use the ContentService.getReader() because we don't need access to the content ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - if (contentData == null || isZeroLengthOfficeDoc(contentData)) + if (contentData == null) { fail = true; } @@ -145,24 +145,4 @@ public class OnContentUpdateRuleTrigger extends RuleTriggerAbstractBase } } } - - /** - * Indicates whether we are dealing with a zero length office document or not - * - * @param contentData the content details - * @return boolean true if zero length office document, false otherwise - */ - private boolean isZeroLengthOfficeDoc(ContentData contentData) - { - boolean result = false; - if (contentData.getSize() == 0 && - (MimetypeMap.MIMETYPE_WORD.equals(contentData.getMimetype()) == true || - MimetypeMap.MIMETYPE_EXCEL.equals(contentData.getMimetype()) == true || - MimetypeMap.MIMETYPE_PPT.equals(contentData.getMimetype()) == true)) - { - result = true; - } - return result; - } - } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index 77943e958b..fd41d9e3e9 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -151,6 +151,7 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine protected StoreRef companyHomeStore; protected String companyHomePath; + private Map ignoredProperties = new HashMap(3); // Note: jBPM query which is not provided out-of-the-box // TODO: Check jBPM 3.2 and get this implemented in jBPM private final static String COMPLETED_TASKS_QUERY = "select ti " + "from org.jbpm.taskmgmt.exe.TaskInstance as ti " @@ -217,7 +218,14 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine // engine ID public static final String ENGINE_ID = "jbpm"; - + + public JBPMEngine() + { + super(); + ignoredProperties.put(WorkflowModel.PROP_STATUS.getLocalName(), WorkflowModel.PROP_STATUS); + ignoredProperties.put(WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP.getLocalName(), WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP); + ignoredProperties.put(WorkflowModel.PROP_PACKAGE_ACTION_GROUP.getLocalName(), WorkflowModel.PROP_PACKAGE_ACTION_GROUP); + } /** * Sets the JBPM Template used for accessing JBoss JBPM in the correct * context @@ -3150,7 +3158,7 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine */ protected void setDefaultTaskProperties(TaskInstance instance) { - Map existingValues = getTaskProperties(instance, true); + Map existingValues = getTaskProperties(instance, false); Map defaultValues = new HashMap(); // construct an anonymous type that flattens all mandatory aspects @@ -3163,7 +3171,7 @@ public class JBPMEngine extends AlfrescoBpmEngine implements WorkflowEngine String defaultValue = entry.getValue().getDefaultValue(); if (defaultValue != null) { - if (existingValues.get(entry.getKey()) == null) + if (existingValues.get(entry.getKey()) == null || ignoredProperties.containsValue(entry.getKey())) { defaultValues.put(entry.getKey(), defaultValue); }