diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 3db5cdc8c7..0be8ddfc8b 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -99,18 +99,24 @@ import org.springframework.util.Assert; public class DbNodeServiceImpl extends AbstractNodeServiceImpl { private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class); + private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths"); - + private QNameDAO qnameDAO; + private NodeDaoService nodeDaoService; + private StoreArchiveMap storeArchiveMap; + private NodeService avmNodeService; + private TenantService tenantService; + private AclDaoComponent aclDaoComponent; public DbNodeServiceImpl() { - storeArchiveMap = new StoreArchiveMap(); // in case it is not set + storeArchiveMap = new StoreArchiveMap(); // in case it is not set } /** @@ -140,7 +146,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { this.tenantService = tenantService; } - + public void setAclDaoComponent(AclDaoComponent aclDaoComponent) { this.aclDaoComponent = aclDaoComponent; @@ -149,14 +155,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl /** * Performs a null-safe get of the node * - * @param nodeRef the node to retrieve + * @param nodeRef + * the node to retrieve * @return Returns the node entity (never null) - * @throws InvalidNodeRefException if the referenced node could not be found + * @throws InvalidNodeRefException + * if the referenced node could not be found */ private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException { ParameterCheck.mandatory("nodeRef", nodeRef); - + Node unchecked = nodeDaoService.getNode(nodeRef); if (unchecked == null) { @@ -164,17 +172,20 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } return unchecked; } - + /** * Gets the node status for a live node. - * @param nodeRef the node reference + * + * @param nodeRef + * the node reference * @return Returns the node status, which will not be null and will have a live node attached. - * @throws InvalidNodeRefException if the node is deleted or never existed + * @throws InvalidNodeRefException + * if the node is deleted or never existed */ public NodeStatus getNodeStatusNotNull(NodeRef nodeRef) throws InvalidNodeRefException { ParameterCheck.mandatory("nodeRef", nodeRef); - + NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, false); if (nodeStatus == null || nodeStatus.getNode() == null) { @@ -182,7 +193,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } return nodeStatus; } - + public boolean exists(StoreRef storeRef) { Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); @@ -190,31 +201,29 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // done return exists; } - + public boolean exists(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - + Node node = nodeDaoService.getNode(nodeRef); boolean exists = (node != null); // done return exists; } - + public Status getNodeStatus(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - + NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, false); - if (nodeStatus == null) // node never existed + if (nodeStatus == null) // node never existed { return null; } else { - return new NodeRef.Status( - nodeStatus.getTransaction().getChangeTxnId(), - nodeStatus.isDeleted()); + return new NodeRef.Status(nodeStatus.getTransaction().getChangeTxnId(), nodeStatus.isDeleted()); } } @@ -230,17 +239,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl StoreRef storeRef = store.getStoreRef(); try { - if (tenantService.isEnabled()) - { - String currentUser = AuthenticationUtil.getCurrentUserName(); - - // MT: return tenant stores only (although for super System return all stores - as used by ConfigurationChecker, IndexRecovery, IndexBackup etc) - if ((currentUser == null) || (! currentUser.equals(AuthenticationUtil.getSystemUserName()))) - { - tenantService.checkDomain(storeRef.getIdentifier()); - storeRef = tenantService.getBaseName(storeRef); - } - } + if (tenantService.isEnabled()) + { + String currentUser = AuthenticationUtil.getCurrentUserName(); + + // MT: return tenant stores only (although for super System return all stores - as used by + // ConfigurationChecker, IndexRecovery, IndexBackup etc) + if ((currentUser == null) || (!currentUser.equals(AuthenticationUtil.getSystemUserName()))) + { + tenantService.checkDomain(storeRef.getIdentifier()); + storeRef = tenantService.getBaseName(storeRef); + } + } storeRefs.add(storeRef); } @@ -255,55 +265,54 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Return them all. return storeRefs; } - + /** * Defers to the typed service + * * @see StoreDaoService#createWorkspace(String) */ public StoreRef createStore(String protocol, String identifier) { - StoreRef storeRef = new StoreRef(protocol, identifier); - + StoreRef storeRef = new StoreRef(protocol, identifier); + // check that the store does not already exist Store store = nodeDaoService.getStore(protocol, identifier); if (store != null) { throw new StoreExistsException("Unable to create a store that already exists: " + storeRef, storeRef); } - + // invoke policies invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, storeRef); - + // create a new one store = nodeDaoService.createStore(protocol, identifier); // get the root node Node rootNode = store.getRootNode(); NodeRef rootNodeRef = tenantService.getBaseName(rootNode.getNodeRef()); - + // assign the root aspect - this is expected of all roots, even store roots - addAspect(rootNodeRef, - ContentModel.ASPECT_ROOT, - Collections.emptyMap()); - + addAspect(rootNodeRef, ContentModel.ASPECT_ROOT, Collections. emptyMap()); + // Bind root permission - - if(aclDaoComponent != null) + + if (aclDaoComponent != null) { SimpleAccessControlListProperties properties = DMPermissionsDaoComponentImpl.getDefaultProperties(); Long id = aclDaoComponent.createAccessControlList(properties); DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id); rootNode.setAccessControlList(acl); } - + // invoke policies invokeOnCreateStore(rootNodeRef); - + // done if (!store.getStoreRef().equals(storeRef)) { throw new RuntimeException("Incorrect store reference"); } - + return storeRef; } @@ -321,9 +330,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { throw new InvalidStoreRefException("Unable to delete a store that does not exist: " + storeRef, storeRef); } - + // TODO invoke policies - e.g. tell indexer to delete index - //invokeBeforeDeleteStore(ContentModel.TYPE_STOREROOT, storeRef); + // invokeBeforeDeleteStore(ContentModel.TYPE_STOREROOT, storeRef); // (hard) delete store nodeDaoService.deleteStore(protocol, identifier); @@ -352,35 +361,28 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl /** * @see #createNode(NodeRef, QName, QName, QName, Map) */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName) + public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName, QName nodeTypeQName) { return this.createNode(parentRef, assocTypeQName, assocQName, nodeTypeQName, null); } /** - * @see org.alfresco.service.cmr.repository.NodeService#createNode(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, java.util.Map) + * @see org.alfresco.service.cmr.repository.NodeService#createNode(org.alfresco.service.cmr.repository.NodeRef, + * org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, + * org.alfresco.service.namespace.QName, java.util.Map) */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName, - Map properties) + public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName, QName nodeTypeQName, Map properties) { Assert.notNull(parentRef); Assert.notNull(assocTypeQName); Assert.notNull(assocQName); - + // Get the parent node Node parentNode = getNodeNotNull(parentRef); // null property map is allowed if (properties == null) - { + { properties = new HashMap(); } else @@ -388,62 +390,57 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Copy the incomming property map since we may need to modify it later properties = new HashMap(properties); } - + // Invoke policy behaviour invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); - + // get the store that the parent belongs to Store store = nodeDaoService.getStore(parentRef.getStoreRef().getProtocol(), parentRef.getStoreRef().getIdentifier()); if (store == null) { throw new RuntimeException("No store found for parent node: " + parentRef); } - + // check the node type TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName); if (nodeTypeDef == null) { throw new InvalidTypeException(nodeTypeQName); } - + // get/generate an ID for the node String newId = generateGuid(properties); - + // create the node instance Node childNode = nodeDaoService.newNode(store, newId, nodeTypeQName); NodeRef childNodeRef = tenantService.getBaseName(childNode.getNodeRef()); // We now have enough to declare the child association creation invokeBeforeCreateChildAssociation(parentRef, childNodeRef, assocTypeQName, assocQName, true); - + // Create the association - ChildAssoc childAssoc = nodeDaoService.newChildAssoc( - parentNode, - childNode, - true, - assocTypeQName, - assocQName); - + ChildAssoc childAssoc = nodeDaoService.newChildAssoc(parentNode, childNode, true, assocTypeQName, assocQName); + // Set the default property values addDefaultPropertyValues(nodeTypeDef, properties); - + // Add the default aspects to the node - addDefaultAspects(nodeTypeDef, childNode, properties); - + addDefaultAspects(nodeTypeDef, childNode, properties); + // set the properties - it is a new node so only set properties if there are any Map propertiesBefore = getPropertiesImpl(childNode); Map propertiesAfter = null; if (properties.size() > 0) { propertiesAfter = setPropertiesImpl(childNode, properties); - } + } // Ensure child uniqueness - setChildUniqueName(childNode); // ensure uniqueness + setChildUniqueName(childNode); // ensure uniqueness ChildAssociationRef childAssocRef = tenantService.getBaseName(childAssoc.getChildAssocRef()); - + // permissions behaviour - if(aclDaoComponent != null) + if (aclDaoComponent != null) { DbAccessControlList inherited = parentNode.getAccessControlList(); if (inherited == null) @@ -455,7 +452,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl childNode.setAccessControlList(aclDaoComponent.getDbAccessControlList(aclDaoComponent.getInheritedAccessControlList(inherited.getId()))); } } - + // Invoke policy behaviour invokeOnCreateNode(childAssocRef); invokeOnCreateChildAssociation(childAssocRef, true); @@ -463,11 +460,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { invokeOnUpdateProperties(childAssocRef.getChildRef(), propertiesBefore, propertiesAfter); } - + // done return childAssocRef; } - + /** * Add the default aspects to a given node * @@ -476,10 +473,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl private void addDefaultAspects(ClassDefinition classDefinition, Node node, Map properties) { NodeRef nodeRef = node.getNodeRef(); - + // get the mandatory aspects for the node type List defaultAspectDefs = classDefinition.getDefaultAspects(); - + // add all the aspects to the node Set nodeAspects = node.getAspects(); for (AspectDefinition defaultAspectDef : defaultAspectDefs) @@ -490,36 +487,31 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl nodeAspects.add(defaultAspectQNameEntity.getId()); addDefaultPropertyValues(defaultAspectDef, properties); invokeOnAddAspect(nodeRef, defaultAspectQName); - + // Now add any default aspects for this aspect addDefaultAspects(defaultAspectDef, node, properties); } } - + /** * Drops the old primary association and creates a new one */ - public ChildAssociationRef moveNode( - NodeRef nodeToMoveRef, - NodeRef newParentRef, - QName assocTypeQName, - QName assocQName) - throws InvalidNodeRefException + public ChildAssociationRef moveNode(NodeRef nodeToMoveRef, NodeRef newParentRef, QName assocTypeQName, QName assocQName) throws InvalidNodeRefException { Assert.notNull(nodeToMoveRef); Assert.notNull(newParentRef); Assert.notNull(assocTypeQName); Assert.notNull(assocQName); - + // check the node references Node nodeToMove = getNodeNotNull(nodeToMoveRef); Node newParentNode = getNodeNotNull(newParentRef); // get the primary parent assoc ChildAssoc oldAssoc = nodeDaoService.getPrimaryParentAssoc(nodeToMove); ChildAssociationRef oldAssocRef = tenantService.getBaseName(oldAssoc.getChildAssocRef()); - + boolean movingStore = !nodeToMoveRef.getStoreRef().equals(newParentRef.getStoreRef()); - + // data needed for policy invocation QName nodeToMoveTypeQName = nodeToMove.getTypeQName().getQName(); Set nodeToMoveAspects = nodeToMove.getAspects(); @@ -535,21 +527,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeBeforeDeleteChildAssociation(oldAssocRef); invokeBeforeCreateChildAssociation(newParentRef, nodeToMoveRef, assocTypeQName, assocQName, false); } - + // remove the child assoc from the old parent // don't cascade as we will still need the node afterwards nodeDaoService.deleteChildAssoc(oldAssoc, false); // create a new assoc - ChildAssoc newAssoc = nodeDaoService.newChildAssoc( - newParentNode, - nodeToMove, - true, - assocTypeQName, - assocQName); - setChildUniqueName(nodeToMove); // ensure uniqueness + ChildAssoc newAssoc = nodeDaoService.newChildAssoc(newParentNode, nodeToMove, true, assocTypeQName, assocQName); + setChildUniqueName(nodeToMove); // ensure uniqueness ChildAssociationRef newAssocRef = tenantService.getBaseName(newAssoc.getChildAssocRef()); - + // If the node is moving stores, then drag the node hierarchy with it if (movingStore) { @@ -559,33 +546,64 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // the node reference will have changed too nodeToMoveRef = nodeToMove.getNodeRef(); } - + // check that no cyclic relationships have been created getPaths(nodeToMoveRef, false); // Fix inherited permissions - - if(aclDaoComponent != null) + + if (aclDaoComponent != null) { - Long targetAcl = newAssoc.getChild().getAccessControlList().getId(); - AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAcl); - Boolean inherits = aclProperties.getInherits(); - if((inherits != null) && (inherits.booleanValue())) + if (newAssoc.getChild().getAccessControlList() != null) { - Long parentAcl = newAssoc.getParent().getAccessControlList().getId(); - Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl); - if(aclProperties.getAclType() == ACLType.DEFINING) + Long targetAcl = newAssoc.getChild().getAccessControlList().getId(); + AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAcl); + Boolean inherits = aclProperties.getInherits(); + if ((inherits != null) && (inherits.booleanValue())) { - aclDaoComponent.enableInheritance(targetAcl, parentAcl); - } - else if(aclProperties.getAclType() == ACLType.SHARED) - { - DMAccessControlListDAO.setFixedAcls(newAssoc.getChildAssocRef().getChildRef(), inheritedAcl, true, this, aclDaoComponent, nodeDaoService); + if (newAssoc.getParent().getAccessControlList() != null) + { + Long parentAcl = newAssoc.getParent().getAccessControlList().getId(); + Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl); + if (aclProperties.getAclType() == ACLType.DEFINING) + { + aclDaoComponent.enableInheritance(targetAcl, parentAcl); + } + else if (aclProperties.getAclType() == ACLType.SHARED) + { + DMAccessControlListDAO.setFixedAcls(newAssoc.getChildAssocRef().getChildRef(), inheritedAcl, true, this, aclDaoComponent, nodeDaoService); + } + } + else + { + if (aclProperties.getAclType() == ACLType.DEFINING) + { + + // there is nothing to inherit from so clear out any inherited aces + aclDaoComponent.deleteInheritedAccessControlEntries(targetAcl); + } + else if (aclProperties.getAclType() == ACLType.SHARED) + { + // there is nothing to inherit + nodeToMove.setAccessControlList(null); + } + + // throw new IllegalStateException("Share bug"); + } } } - + else + { + if (newAssoc.getParent().getAccessControlList() != null) + { + Long parentAcl = newAssoc.getParent().getAccessControlList().getId(); + Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl); + DMAccessControlListDAO.setFixedAcls(newAssoc.getChildAssocRef().getChildRef(), inheritedAcl, true, this, aclDaoComponent, nodeDaoService); + } + } + } - + // invoke policy behaviour if (movingStore) { @@ -596,7 +614,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl nodeToMoveAspectQNames.add(nodeToMoveAspectQName); } // TODO for now indicate that the node has been archived to prevent the version history from being removed - // in the future a onMove policy could be added and remove the need for onDelete and onCreate to be fired here + // in the future a onMove policy could be added and remove the need for onDelete and onCreate to be fired + // here invokeOnDeleteNode(oldAssocRef, nodeToMoveTypeQName, nodeToMoveAspectQNames, true); invokeOnCreateNode(newAssoc.getChildAssocRef()); } @@ -606,10 +625,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeOnDeleteChildAssociation(oldAssoc.getChildAssocRef()); } invokeOnMoveNode(oldAssocRef, newAssocRef); - + // update the node status nodeDaoService.recordChangeId(nodeToMoveRef); - + // done return newAssoc.getChildAssocRef(); } @@ -619,18 +638,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // get nodes Node parentNode = getNodeNotNull(childAssocRef.getParentRef()); Node childNode = getNodeNotNull(childAssocRef.getChildRef()); - - ChildAssoc assoc = nodeDaoService.getChildAssoc( - parentNode, - childNode, - childAssocRef.getTypeQName(), - childAssocRef.getQName()); + + ChildAssoc assoc = nodeDaoService.getChildAssoc(parentNode, childNode, childAssocRef.getTypeQName(), childAssocRef.getQName()); if (assoc == null) { - throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + - " assoc: " + childAssocRef + "\n" + - " index: " + index, - childAssocRef); + throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + " assoc: " + childAssocRef + "\n" + " index: " + index, childAssocRef); } // set the index assoc.setIndex(index); @@ -643,9 +655,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node node = getNodeNotNull(nodeRef); return node.getTypeQName().getQName(); } - + /** - * @see org.alfresco.service.cmr.repository.NodeService#setType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) + * @see org.alfresco.service.cmr.repository.NodeService#setType(org.alfresco.service.cmr.repository.NodeRef, + * org.alfresco.service.namespace.QName) */ public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException { @@ -656,32 +669,28 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl throw new InvalidTypeException(typeQName); } Node node = getNodeNotNull(nodeRef); - + // Invoke policies invokeBeforeUpdateNode(nodeRef); - + // Ensure that we have a QName entity to represent the type QNameEntity typeQNameEntity = qnameDAO.getOrCreateQNameEntity(typeQName); // Get the node and set the new type node.setTypeQName(typeQNameEntity); - + // Add the default aspects to the node (update the properties with any new default values) Map properties = this.getPropertiesImpl(node); addDefaultAspects(nodeTypeDef, node, properties); this.setProperties(nodeRef, properties); - + // Invoke policies invokeOnUpdateNode(nodeRef); } - + /** * @see Node#getAspects() */ - public void addAspect( - NodeRef nodeRef, - QName aspectTypeQName, - Map aspectProperties) - throws InvalidNodeRefException, InvalidAspectException + public void addAspect(NodeRef nodeRef, QName aspectTypeQName, Map aspectProperties) throws InvalidNodeRefException, InvalidAspectException { // check that the aspect is legal AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); @@ -689,49 +698,48 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName, aspectTypeQName); } - + Node node = getNodeNotNull(nodeRef); - + // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); invokeBeforeAddAspect(nodeRef, aspectTypeQName); - + // attach the properties to the current node properties Map nodeProperties = getPropertiesImpl(node); - + if (aspectProperties != null) { nodeProperties.putAll(aspectProperties); } - + // Set any default property values that appear on the aspect addDefaultPropertyValues(aspectDef, nodeProperties); - + // Add any dependent aspect addDefaultAspects(aspectDef, node, nodeProperties); - + // Set the property values back on the node setProperties(nodeRef, nodeProperties); - + // Get the persistale QNameEntity for the aspect QNameEntity aspectTypeQNameEntity = qnameDAO.getOrCreateQNameEntity(aspectTypeQName); // physically attach the aspect to the node if (node.getAspects().add(aspectTypeQNameEntity.getId()) == true) - { + { // Invoke policy behaviours invokeOnUpdateNode(nodeRef); invokeOnAddAspect(nodeRef, aspectTypeQName); - + // update the node status nodeDaoService.recordChangeId(nodeRef); - } + } } /** * @see Node#getAspects() */ - public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException + public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) throws InvalidNodeRefException, InvalidAspectException { // get the aspect AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); @@ -742,7 +750,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // get the node Node node = getNodeNotNull(nodeRef); Set nodeAspects = node.getAspects(); - + // Get the persistale QNameEntity for the aspect QNameEntity aspectTypeQNameEntity = qnameDAO.getOrCreateQNameEntity(aspectTypeQName); if (!nodeAspects.contains(aspectTypeQNameEntity.getId())) @@ -750,22 +758,22 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // The aspect isn't present so just leave it return; } - + // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); - + // remove the aspect, if present nodeAspects.remove(aspectTypeQNameEntity.getId()); Map nodeProperties = node.getProperties(); - Map propertyDefs = aspectDef.getProperties(); + Map propertyDefs = aspectDef.getProperties(); for (QName propertyQName : propertyDefs.keySet()) { QNameEntity propertyQNameEntity = qnameDAO.getOrCreateQNameEntity(propertyQName); nodeProperties.remove(propertyQNameEntity.getId()); } - + // Remove child associations Map childAssocDefs = aspectDef.getChildAssociations(); Collection childAssocs = nodeDaoService.getChildAssocs(node); @@ -780,7 +788,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // The association is of a type that should be removed nodeDaoService.deleteChildAssoc(childAssoc, true); } - + // Remove regular associations Map assocDefs = aspectDef.getAssociations(); List nodeAssocs = nodeDaoService.getTargetNodeAssocs(node); @@ -795,11 +803,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Delete the association nodeDaoService.deleteNodeAssoc(nodeAssoc); } - + // Invoke policy behaviours invokeOnUpdateNode(nodeRef); invokeOnRemoveAspect(nodeRef, aspectTypeQName); - + // update the node status nodeDaoService.recordChangeId(nodeRef); } @@ -845,13 +853,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node node = getNodeNotNull(nodeRef); boolean requiresDelete = false; - + // Invoke policy behaviours invokeBeforeDeleteNode(nodeRef); - + // get the primary parent-child relationship before it is gone ChildAssociationRef childAssocRef = getPrimaryParent(nodeRef); - + // get type and aspect QNames as they will be unavailable after the delete QName nodeTypeQName = node.getTypeQName().getQName(); Set nodeAspectQNameEntityIds = node.getAspects(); @@ -859,30 +867,29 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Get QNameEntity for subsequent checks QNameEntity aspectTempQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_TEMPORARY); QNameEntity aspectWorkingCopyQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_WORKING_COPY); - + // check if we need to archive the node StoreRef archiveStoreRef = null; - if (nodeAspectQNameEntityIds.contains(aspectTempQNameEntity.getId()) || - nodeAspectQNameEntityIds.contains(aspectWorkingCopyQNameEntity.getId())) + if (nodeAspectQNameEntityIds.contains(aspectTempQNameEntity.getId()) || nodeAspectQNameEntityIds.contains(aspectWorkingCopyQNameEntity.getId())) { - // The node is either temporary or a working copy. - // It can not be archived. - requiresDelete = true; + // The node is either temporary or a working copy. + // It can not be archived. + requiresDelete = true; } else { - StoreRef storeRef = nodeRef.getStoreRef(); + StoreRef storeRef = nodeRef.getStoreRef(); - // remove tenant domain - to retrieve archive store from map - archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); - // get the type and check if we need archiving - TypeDefinition typeDef = dictionaryService.getType(nodeTypeQName); - if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) - { - requiresDelete = true; - } + // remove tenant domain - to retrieve archive store from map + archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + // get the type and check if we need archiving + TypeDefinition typeDef = dictionaryService.getType(nodeTypeQName); + if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) + { + requiresDelete = true; + } } - + if (requiresDelete) { // perform a normal deletion @@ -904,7 +911,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // The archive performs a move, which will fire the appropriate OnDeleteNode } } - + public ChildAssociationRef addChild(NodeRef parentRef, NodeRef childRef, QName assocTypeQName, QName assocQName) { // get the parent node and ensure that it is a container node @@ -914,19 +921,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Invoke policy behaviours invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName, false); - + // make the association - ChildAssoc assoc = nodeDaoService.newChildAssoc( - parentNode, - childNode, - false, - assocTypeQName, - assocQName); + ChildAssoc assoc = nodeDaoService.newChildAssoc(parentNode, childNode, false, assocTypeQName, assocQName); // ensure name uniqueness setChildUniqueName(childNode); ChildAssociationRef assocRef = assoc.getChildAssocRef(); NodeRef childNodeRef = assocRef.getChildRef(); - + // check that the child addition of the child has not created a cyclic relationship // this functionality is provided for free in getPath getPaths(childNodeRef, false); @@ -936,7 +938,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // update the node status nodeDaoService.recordChangeId(childNodeRef); - + return assoc.getChildAssocRef(); } @@ -945,16 +947,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node parentNode = getNodeNotNull(parentRef); Node childNode = getNodeNotNull(childRef); Long childNodeId = childNode.getId(); - + // get all the child assocs ChildAssociationRef primaryAssocRef = null; Collection assocs = nodeDaoService.getChildAssocs(parentNode); - assocs = new HashSet(assocs); // copy set as we will be modifying it + assocs = new HashSet(assocs); // copy set as we will be modifying it for (ChildAssoc assoc : assocs) { if (!assoc.getChild().getId().equals(childNodeId)) { - continue; // not a matching association + continue; // not a matching association } ChildAssociationRef assocRef = assoc.getChildAssocRef(); // Is this a primary association? @@ -967,7 +969,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { // delete the association instance - it is not primary invokeBeforeDeleteChildAssociation(assocRef); - nodeDaoService.deleteChildAssoc(assoc, true); // cascade + nodeDaoService.deleteChildAssoc(assoc, true); // cascade invokeOnDeleteChildAssociation(assocRef); } } @@ -985,7 +987,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // done } - + public boolean removeChildAssociation(ChildAssociationRef childAssocRef) { Node parentNode = getNodeNotNull(childAssocRef.getParentRef()); @@ -1019,9 +1021,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } if (assoc.getIsPrimary()) { - throw new IllegalArgumentException( - "removeSeconaryChildAssociation can not be applied to a primary association: \n" + - " Child Assoc: " + assoc); + throw new IllegalArgumentException("removeSeconaryChildAssociation can not be applied to a primary association: \n" + " Child Assoc: " + assoc); } // Delete the secondary association nodeDaoService.deleteChildAssoc(assoc, false); @@ -1033,11 +1033,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } /** - * Remove properties that should not be persisted as general properties. Where necessary, the - * properties are set on the node. + * Remove properties that should not be persisted as general properties. Where necessary, the properties are set on + * the node. * - * @param node the node to set properties on - * @param properties properties to change + * @param node + * the node to set properties on + * @param properties + * properties to change */ private void extractIntrinsicProperties(Node node, Map properties) { @@ -1046,26 +1048,27 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl properties.remove(ContentModel.PROP_NODE_UUID); properties.remove(ContentModel.PROP_NODE_DBID); } - + /** - * Adds all properties used by the - * {@link ContentModel#ASPECT_REFERENCEABLE referencable aspect}. + * Adds all properties used by the {@link ContentModel#ASPECT_REFERENCEABLE referencable aspect}. *

- * This method can be used to ensure that the values used by the aspect - * are present as node properties. + * This method can be used to ensure that the values used by the aspect are present as node properties. *

- * This method also ensures that the {@link ContentModel#PROP_NAME name property} - * is always present as a property on a node. + * This method also ensures that the {@link ContentModel#PROP_NAME name property} is always present as a property on + * a node. * - * @param node the node with the values - * @param nodeRef the node reference containing the values required - * @param properties the node properties + * @param node + * the node with the values + * @param nodeRef + * the node reference containing the values required + * @param properties + * the node properties */ private void addIntrinsicProperties(Node node, Map properties) { NodeRef nodeRef = tenantService.getBaseName(node.getNodeRef()); properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol()); - properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); + properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId()); properties.put(ContentModel.PROP_NODE_DBID, node.getId()); // add the ID as the name, if required @@ -1080,21 +1083,21 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node node = getNodeNotNull(nodeRef); return getPropertiesImpl(node); } - + private Map getPropertiesImpl(Node node) throws InvalidNodeRefException { - Map propDefs = dictionaryService.getPropertyDefs(node.getTypeQName().getQName()); + Map propDefs = dictionaryService.getPropertyDefs(node.getTypeQName().getQName()); Map nodeProperties = node.getProperties(); Map ret = new HashMap(nodeProperties.size()); // copy values - for (Map.Entry entry: nodeProperties.entrySet()) + for (Map.Entry entry : nodeProperties.entrySet()) { Long propertyQNameId = entry.getKey(); QName propertyQName = qnameDAO.getQNameEntity(propertyQNameId).getQName(); PropertyValue propertyValue = entry.getValue(); // get the property definition PropertyDefinition propertyDef = propDefs.get(propertyQName); - + // convert to the correct type Serializable value = makeSerializableValue(propertyDef, propertyValue); // copy across @@ -1105,12 +1108,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // done return ret; } - + public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException { // get the property from the node Node node = getNodeNotNull(nodeRef); - + // spoof referencable properties if (qname.equals(ContentModel.PROP_STORE_PROTOCOL)) { @@ -1129,7 +1132,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { return node.getId(); } - + // Get the QName entity QNameEntity qnameEntity = qnameDAO.getQNameEntity(qname); if (qnameEntity == null) @@ -1141,16 +1144,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { Map properties = node.getProperties(); PropertyValue propertyValue = properties.get(qnameEntity.getId()); - + // check if we need to provide a spoofed name if (propertyValue == null && qname.equals(ContentModel.PROP_NAME)) { return nodeRef.getId(); } - + // Convert any NodeRefs using multi-tenant translation PropertyDefinition propertyDef = dictionaryService.getProperty(qname); - + // convert to the correct type Serializable value = makeSerializableValue(propertyDef, propertyValue); // done @@ -1159,21 +1162,21 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } /** - * Ensures that all required properties are present on the node and copies the - * property values to the Node. + * Ensures that all required properties are present on the node and copies the property values to the + * Node. *

- * To remove a property, remove it from the map before calling this method. - * Null-valued properties are allowed. + * To remove a property, remove it from the map before calling this method. Null-valued properties are + * allowed. *

- * If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into - * a real nulls when the properties are requested again. + * If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into a real + * nulls when the properties are requested again. * * @see Node#getProperties() */ public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException { Node node = getNodeNotNull(nodeRef); - + // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); @@ -1181,33 +1184,35 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Map propertiesBefore = getPropertiesImpl(node); Map propertiesAfter = setPropertiesImpl(node, properties); - setChildUniqueName(node); // ensure uniqueness + setChildUniqueName(node); // ensure uniqueness // Invoke policy behaviours invokeOnUpdateNode(nodeRef); invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); } - + /** - * Does the work of setting the property values. Returns a map containing the state of the properties after the set + * Does the work of setting the property values. Returns a map containing the state of the properties after the set * operation is complete. * - * @param node the node - * @param properties the map of property values - * @return the map of property values after the set operation is complete + * @param node + * the node + * @param properties + * the map of property values + * @return the map of property values after the set operation is complete * @throws InvalidNodeRefException */ private Map setPropertiesImpl(Node node, Map properties) throws InvalidNodeRefException { ParameterCheck.mandatory("properties", properties); - + // remove referencable properties extractIntrinsicProperties(node, properties); - + // copy properties onto node Map nodeProperties = node.getProperties(); nodeProperties.clear(); - + // check the property type and copy the values across for (QName propertyQName : properties.keySet()) { @@ -1219,59 +1224,61 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl PropertyValue propertyValue = makePropertyValue(propertyDef, value); nodeProperties.put(propertyQNameEntity.getId(), propertyValue); } - + // update the node status NodeRef nodeRef = node.getNodeRef(); nodeDaoService.recordChangeId(nodeRef); - + // Return the properties after return Collections.unmodifiableMap(properties); } - + /** - * Gets the properties map, sets the value (null is allowed) and checks that the new set - * of properties is valid. + * Gets the properties map, sets the value (null is allowed) and checks that the new set of properties is valid. * * @see DbNodeServiceImpl.NullPropertyValue */ public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException { Assert.notNull(qname); - + // get the node Node node = getNodeNotNull(nodeRef); - + // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); - + // Do the set operation Map propertiesBefore = getPropertiesImpl(node); Map propertiesAfter = setPropertyImpl(node, qname, value); - + if (qname.equals(ContentModel.PROP_NAME)) { - setChildUniqueName(node); // ensure uniqueness + setChildUniqueName(node); // ensure uniqueness } // Invoke policy behaviours invokeOnUpdateNode(nodeRef); invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); } - + /** - * Does the work of setting a property value. Returns the values of the properties after the set operation is + * Does the work of setting a property value. Returns the values of the properties after the set operation is * complete. * - * @param node the node - * @param qname the qname of the property - * @param value the value of the property - * @return the values of the properties after the set operation is complete + * @param node + * the node + * @param qname + * the qname of the property + * @param value + * the value of the property + * @return the values of the properties after the set operation is complete * @throws InvalidNodeRefException */ private Map setPropertyImpl(Node node, QName qname, Serializable value) throws InvalidNodeRefException { NodeRef nodeRef = node.getNodeRef(); - + Map properties = node.getProperties(); PropertyDefinition propertyDef = dictionaryService.getProperty(qname); // Get the persistable key @@ -1279,26 +1286,26 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // get a persistable value PropertyValue propertyValue = makePropertyValue(propertyDef, value); properties.put(qnameEntity.getId(), propertyValue); - + // update the node status nodeDaoService.recordChangeId(nodeRef); - - return getPropertiesImpl(node); + + return getPropertiesImpl(node); } - + public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException { if (qname.equals(ContentModel.PROP_NAME)) { throw new UnsupportedOperationException("The property " + qname + " may not be removed individually"); } - + // Get the node Node node = getNodeNotNull(nodeRef); - + // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); - + // Get the persistable QNameEntity QNameEntity qnameEntity = qnameDAO.getOrCreateQNameEntity(qname); // Get the values before @@ -1308,7 +1315,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl properties.remove(qnameEntity.getId()); // Get the values afterwards Map propertiesAfter = getPropertiesImpl(node); - + // Invoke policy behaviours invokeOnUpdateNode(nodeRef); invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); @@ -1358,7 +1365,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // no match - ignore continue; } - ChildAssociationRef childAssocRef = tenantService.getBaseName(assoc.getChildAssocRef()); + ChildAssociationRef childAssocRef = tenantService.getBaseName(assoc.getChildAssocRef()); results.add(childAssocRef); } // done @@ -1371,13 +1378,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) { Node node = getNodeNotNull(nodeRef); - + Collection childAssocRefs = null; // if the type is the wildcard type, and the qname is not a search, then use a shortcut query if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL) && qnamePattern instanceof QName) { // get all child associations with the specific qualified name - childAssocRefs = nodeDaoService.getChildAssocRefs(node, (QName)qnamePattern); + childAssocRefs = nodeDaoService.getChildAssocRefs(node, (QName) qnamePattern); } else { @@ -1401,7 +1408,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // done return orderedList; } - + private List reorderChildAssocs(Collection childAssocRefs) { // shortcut if there are no assocs @@ -1412,11 +1419,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // sort results ArrayList orderedList = new ArrayList(childAssocRefs); Collections.sort(orderedList); - + // list of results int nthSibling = 0; Iterator iterator = orderedList.iterator(); - while(iterator.hasNext()) + while (iterator.hasNext()) { ChildAssociationRef childAssocRef = iterator.next(); childAssocRef.setNthSibling(nthSibling); @@ -1459,8 +1466,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return assocRef; } - public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException, AssociationExistsException + public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) throws InvalidNodeRefException, AssociationExistsException { Node sourceNode = getNodeNotNull(sourceRef); Node targetNode = getNodeNotNull(targetRef); @@ -1476,12 +1482,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Invoke policy behaviours invokeOnCreateAssociation(assocRef); - + return assocRef; } - public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException + public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) throws InvalidNodeRefException { Node sourceNode = getNodeNotNull(sourceRef); Node targetNode = getNodeNotNull(targetRef); @@ -1493,10 +1498,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return; } AssociationRef assocRef = assoc.getNodeAssocRef(); - + // delete it nodeDaoService.deleteNodeAssoc(assoc); - + // Invoke policy behaviours invokeOnDeleteAssociation(assocRef); } @@ -1513,7 +1518,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // check qname pattern if (!qnamePattern.isMatch(assocTypeQName)) { - continue; // the assoc name doesn't match the pattern given + continue; // the assoc name doesn't match the pattern given } nodeAssocRefs.add(assoc.getNodeAssocRef()); } @@ -1533,37 +1538,36 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // check qname pattern if (!qnamePattern.isMatch(assocTypeQName)) { - continue; // the assoc name doesn't match the pattern given + continue; // the assoc name doesn't match the pattern given } nodeAssocRefs.add(assoc.getNodeAssocRef()); } // done return nodeAssocRefs; } - + /** * Recursive method used to build up paths from a given node to the root. *

- * Whilst walking up the hierarchy to the root, some nodes may have a root aspect. - * Everytime one of these is encountered, a new path is farmed off, but the method - * continues to walk up the hierarchy. + * Whilst walking up the hierarchy to the root, some nodes may have a root aspect. Everytime one of these is + * encountered, a new path is farmed off, but the method continues to walk up the hierarchy. * - * @param currentNode the node to start from, i.e. the child node to work upwards from - * @param currentPath the path from the current node to the descendent that we started from - * @param completedPaths paths that have reached the root are added to this collection - * @param assocStack the parent-child relationships traversed whilst building the path. - * Used to detected cyclic relationships. - * @param primaryOnly true if only the primary parent association must be traversed. - * If this is true, then the only root is the top level node having no parents. + * @param currentNode + * the node to start from, i.e. the child node to work upwards from + * @param currentPath + * the path from the current node to the descendent that we started from + * @param completedPaths + * paths that have reached the root are added to this collection + * @param assocStack + * the parent-child relationships traversed whilst building the path. Used to detected cyclic + * relationships. + * @param primaryOnly + * true if only the primary parent association must be traversed. If this is true, then the only root is + * the top level node having no parents. * @throws CyclicChildRelationshipException */ - private void prependPaths( - final Node currentNode, - final Path currentPath, - Collection completedPaths, - Stack assocStack, - boolean primaryOnly) - throws CyclicChildRelationshipException + private void prependPaths(final Node currentNode, final Path currentPath, Collection completedPaths, Stack assocStack, boolean primaryOnly) + throws CyclicChildRelationshipException { NodeRef currentNodeRef = currentNode.getNodeRef(); // get the parent associations of the given node @@ -1573,23 +1577,19 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // does the current node have a root aspect? boolean isRoot = hasAspect(currentNodeRef, ContentModel.ASPECT_ROOT); boolean isStoreRoot = currentNode.getTypeQName().getQName().equals(ContentModel.TYPE_STOREROOT); - - // look for a root. If we only want the primary root, then ignore all but the top-level root. - if (isRoot && !(primaryOnly && hasParents)) // exclude primary search with parents present + + // look for a root. If we only want the primary root, then ignore all but the top-level root. + if (isRoot && !(primaryOnly && hasParents)) // exclude primary search with parents present { // create a one-sided assoc ref for the root node and prepend to the stack // this effectively spoofs the fact that the current node is not below the root // - we put this assoc in as the first assoc in the path must be a one-sided - // reference pointing to the root node - ChildAssociationRef assocRef = new ChildAssociationRef( - null, - null, - null, - getRootNode(currentNode.getNodeRef().getStoreRef())); + // reference pointing to the root node + ChildAssociationRef assocRef = new ChildAssociationRef(null, null, null, getRootNode(currentNode.getNodeRef().getStoreRef())); // create a path to save and add the 'root' assoc Path pathToSave = new Path(); Path.ChildAssocElement first = null; - for (Path.Element element: currentPath) + for (Path.Element element : currentPath) { if (first == null) { @@ -1603,27 +1603,23 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl if (first != null) { // mimic an association that would appear if the current node was below the root node - // or if first beneath the root node it will make the real thing - ChildAssociationRef updateAssocRef = new ChildAssociationRef( - isStoreRoot ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), - getRootNode(currentNode.getNodeRef().getStoreRef()), - first.getRef().getQName(), - first.getRef().getChildRef()); - Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef); + // or if first beneath the root node it will make the real thing + ChildAssociationRef updateAssocRef = new ChildAssociationRef(isStoreRoot ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), getRootNode(currentNode + .getNodeRef().getStoreRef()), first.getRef().getQName(), first.getRef().getChildRef()); + Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef); pathToSave.prepend(newFirst); } - + Path.Element element = new Path.ChildAssocElement(assocRef); pathToSave.prepend(element); - + // store the path just built completedPaths.add(pathToSave); } if (parentAssocs.size() == 0 && !isRoot) { - throw new RuntimeException("Node without parents does not have root aspect: " + - currentNodeRef); + throw new RuntimeException("Node without parents does not have root aspect: " + currentNodeRef); } // walk up each parent association for (ChildAssoc assoc : parentAssocs) @@ -1632,12 +1628,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl if (assocStack.contains(assoc)) { // the association was present already - throw new CyclicChildRelationshipException( - "Cyclic parent-child relationship detected: \n" + - " current node: " + currentNode + "\n" + - " current path: " + currentPath + "\n" + - " next assoc: " + assoc, - assoc); + throw new CyclicChildRelationshipException("Cyclic parent-child relationship detected: \n" + + " current node: " + currentNode + "\n" + " current path: " + currentPath + "\n" + " next assoc: " + assoc, assoc); } // do we consider only primary assocs? if (primaryOnly && !assoc.getIsPrimary()) @@ -1645,18 +1637,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl continue; } // build a path element - NodeRef parentRef = tenantService.getBaseName(assoc.getParent().getNodeRef()); + NodeRef parentRef = tenantService.getBaseName(assoc.getParent().getNodeRef()); QName qname = assoc.getQname(); NodeRef childRef = tenantService.getBaseName(assoc.getChild().getNodeRef()); boolean isPrimary = assoc.getIsPrimary(); // build a real association reference - ChildAssociationRef assocRef = new ChildAssociationRef( - assoc.getTypeQName().getQName(), - parentRef, - qname, - childRef, - isPrimary, - -1); + ChildAssociationRef assocRef = new ChildAssociationRef(assoc.getTypeQName().getQName(), parentRef, qname, childRef, isPrimary, -1); // Ordering is not important here: We are building distinct paths upwards Path.Element element = new Path.ChildAssocElement(assocRef); // create a new path that builds on the current path @@ -1666,7 +1652,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl path.prepend(element); // get parent node Node parentNode = assoc.getParent(); - + // push the assoc stack, recurse and pop assocStack.push(assoc); prependPaths(parentNode, path, completedPaths, assocStack, primaryOnly); @@ -1681,17 +1667,17 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl */ public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException { - List paths = getPaths(nodeRef, true); // checks primary path count + List paths = getPaths(nodeRef, true); // checks primary path count if (paths.size() == 1) { - return paths.get(0); // we know there is only one + return paths.get(0); // we know there is only one } - throw new RuntimeException("Primary path count not checked"); // checked by getPaths() + throw new RuntimeException("Primary path count not checked"); // checked by getPaths() } /** - * When searching for primaryOnly == true, checks that there is exactly - * one path. + * When searching for primaryOnly == true, checks that there is exactly one path. + * * @see #prependPaths(Node, Path, Collection, Stack, boolean) */ public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException @@ -1706,13 +1692,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Stack assocStack = new Stack(); // call recursive method to sort it out prependPaths(node, currentPath, paths, assocStack, primaryOnly); - + // check that for the primary only case we have exactly one path if (primaryOnly && paths.size() != 1) { throw new RuntimeException("Node has " + paths.size() + " primary paths: " + nodeRef); } - + // done if (loggerPaths.isDebugEnabled()) { @@ -1734,7 +1720,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } return paths; } - + private void archiveNode(NodeRef nodeRef, StoreRef archiveStoreRef) { QNameEntity aspectQNameEntityArchived = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_ARCHIVED); @@ -1743,62 +1729,49 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl QNameEntity propQNameArchivedBy = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_BY); QNameEntity propQNameArchivedDate = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_DATE); QNameEntity propQNameArchivedOriginalParentAssoc = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC); - + NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, false); Node node = nodeStatus.getNode(); ChildAssoc primaryParentAssoc = nodeDaoService.getPrimaryParentAssoc(node); - + // add the aspect Set aspects = node.getAspects(); aspects.add(aspectQNameEntityArchived.getId()); Map properties = node.getProperties(); - PropertyValue archivedByProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY), - AuthenticationUtil.getCurrentUserName()); + PropertyValue archivedByProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY), AuthenticationUtil.getCurrentUserName()); properties.put(propQNameArchivedBy.getId(), archivedByProperty); - PropertyValue archivedDateProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE), - new Date()); + PropertyValue archivedDateProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE), new Date()); properties.put(propQNameArchivedDate.getId(), archivedDateProperty); - PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), - primaryParentAssoc.getChildAssocRef()); + PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), primaryParentAssoc + .getChildAssocRef()); properties.put(propQNameArchivedOriginalParentAssoc.getId(), archivedPrimaryParentNodeRefProperty); PropertyValue originalOwnerProperty = properties.get(propQNameEntityOwner.getId()); PropertyValue originalCreatorProperty = properties.get(propQNameEntityCreator.getId()); if (originalOwnerProperty != null || originalCreatorProperty != null) { QNameEntity propQNameArchivedOriginalOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); - properties.put( - propQNameArchivedOriginalOwner.getId(), - originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty); + properties.put(propQNameArchivedOriginalOwner.getId(), originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty); } - + // change the node ownership QNameEntity ownableAspectQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_OWNABLE); aspects.add(ownableAspectQNameEntity.getId()); - PropertyValue newOwnerProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER), - AuthenticationUtil.getCurrentUserName()); + PropertyValue newOwnerProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER), AuthenticationUtil.getCurrentUserName()); QNameEntity propQNameOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_OWNER); properties.put(propQNameOwner.getId(), newOwnerProperty); - + // move the node NodeRef archiveStoreRootNodeRef = getRootNode(archiveStoreRef); - moveNode( - nodeRef, - archiveStoreRootNodeRef, - ContentModel.ASSOC_CHILDREN, - QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem")); - + moveNode(nodeRef, archiveStoreRootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem")); + // the node reference has changed due to the store move nodeRef = node.getNodeRef(); // as has the node status nodeStatus = nodeDaoService.getNodeStatus(nodeRef, true); - + // get the IDs of all the node's primary children, including its own Map nodeStatusesById = getNodeHierarchy(nodeStatus, null); - + // Archive all the associations between the archived nodes and non-archived nodes for (NodeStatus nodeStatusToArchive : nodeStatusesById.values()) { @@ -1810,14 +1783,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl archiveAssocs(nodeToArchive, nodeStatusesById); } } - + /** - * Performs all the necessary housekeeping involved in changing a node's store. - * This method cascades down through all the primary children of the node as - * well. + * Performs all the necessary housekeeping involved in changing a node's store. This method cascades down through + * all the primary children of the node as well. * - * @param node the node whose store is changing - * @param store the new store for the node + * @param node + * the node whose store is changing + * @param store + * the new store for the node */ private void moveNodeToStore(Node node, Store store) { @@ -1825,7 +1799,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, true); // get the IDs of all the node's primary children, including its own Map nodeStatusesById = getNodeHierarchy(nodeStatus, null); - + // move each node into the archive store for (NodeStatus oldNodeStatus : nodeStatusesById.values()) { @@ -1833,46 +1807,47 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl NodeRef targetStoreNodeRef = new NodeRef(store.getStoreRef(), oldNodeStatus.getKey().getGuid()); if (exists(targetStoreNodeRef)) { - // It is there already. It must be an archive of an earlier version, so just wipe it out + // It is there already. It must be an archive of an earlier version, so just wipe it out Node archivedNode = getNodeNotNull(targetStoreNodeRef); nodeDaoService.deleteNode(archivedNode, true); // We need to flush here as the node deletion may not take effect before the node creation - // is done. As this will only occur during a clash, it is not going to add extra overhead + // is done. As this will only occur during a clash, it is not going to add extra overhead // to the general system performance. nodeDaoService.flush(); } - + Node nodeToMove = oldNodeStatus.getNode(); if (nodeToMove == null) { - // Ignore it. It was moved already. + // Ignore it. It was moved already. continue; } NodeRef oldNodeRef = nodeToMove.getNodeRef(); nodeToMove.setStore(store); NodeRef newNodeRef = nodeToMove.getNodeRef(); - + // update old status oldNodeStatus.setNode(null); // create the new status NodeStatus newNodeStatus = nodeDaoService.getNodeStatus(newNodeRef, true); newNodeStatus.setNode(nodeToMove); - + // Record change IDs nodeDaoService.recordChangeId(oldNodeRef); nodeDaoService.recordChangeId(newNodeRef); - + invokeOnUpdateNode(newNodeRef); } } - + /** - * Fill the map of all primary children below the given node. - * The given node will be added to the map and the method is recursive - * to all primary children. + * Fill the map of all primary children below the given node. The given node will be added to the map and the method + * is recursive to all primary children. * - * @param nodeStatus the status of the node at the top of the hierarchy - * @param nodeStatusesById a map of node statuses that will be reused as the return value + * @param nodeStatus + * the status of the node at the top of the hierarchy + * @param nodeStatusesById + * a map of node statuses that will be reused as the return value * @return Returns a map of nodes in the hierarchy keyed by their IDs */ private Map getNodeHierarchy(NodeStatus nodeStatus, Map nodeStatusesById) @@ -1883,7 +1858,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // this is the entry into the hierarchy - flush to ensure we are not stale nodeDaoService.flush(); } - + Node node = nodeStatus.getNode(); if (node == null) { @@ -1908,15 +1883,17 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } return nodeStatusesById; } - + /** - * Archive all associations to and from the given node, with the - * exception of associations to or from nodes in the given map. + * Archive all associations to and from the given node, with the exception of associations to or from nodes in the + * given map. *

* Primary parent associations are also ignored. * - * @param node the node whose associations must be archived - * @param nodesById a map of nodes partaking in the archival process + * @param node + * the node whose associations must be archived + * @param nodesById + * a map of nodes partaking in the archival process */ private void archiveAssocs(Node node, Map nodeStatusesById) { @@ -1991,13 +1968,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { nodeDaoService.deleteNodeAssoc(assoc); } - + // add archived aspect QNameEntity archivedAssocsAspectQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_ARCHIVED_ASSOCS); node.getAspects().add(archivedAssocsAspectQNameEntity.getId()); // set properties Map properties = node.getProperties(); - + if (archivedParentAssocRefs.size() > 0) { QNameEntity propQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); @@ -2050,7 +2027,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl QNameEntity propQNameEntityArchivedBy = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_BY); QNameEntity propQNameEntityArchivedDate = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_DATE); QNameEntity propQNameEntityOrigOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); - + NodeStatus archivedNodeStatus = getNodeStatusNotNull(archivedNodeRef); Node archivedNode = archivedNodeStatus.getNode(); Set aspects = archivedNode.getAspects(); @@ -2060,19 +2037,19 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { throw new AlfrescoRuntimeException("The node to archive is not an archive node"); } - ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), - properties.get(propQNameEntityOrigParentAssoc.getId())); + ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue(dictionaryService + .getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), properties.get(propQNameEntityOrigParentAssoc.getId())); PropertyValue originalOwnerProperty = properties.get(propQNameEntityOrigOwner.getId()); - + // remove the archived aspect - removeAspect(archivedNodeRef, ContentModel.ASPECT_ARCHIVED); // allow policy to fire, e.g. for DictionaryModelType - + removeAspect(archivedNodeRef, ContentModel.ASPECT_ARCHIVED); // allow policy to fire, e.g. for + // DictionaryModelType + properties.remove(propQNameEntityOrigParentAssoc.getId()); properties.remove(propQNameEntityArchivedBy.getId()); properties.remove(propQNameEntityArchivedDate.getId()); properties.remove(propQNameEntityOrigOwner.getId()); - + // restore the original ownership if (originalOwnerProperty != null) { @@ -2080,7 +2057,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl aspects.add(ownableAspectQNameEntity.getId()); properties.put(propQNameEntityOwner.getId(), originalOwnerProperty); } - + if (destinationParentNodeRef == null) { // we must restore to the original location @@ -2097,11 +2074,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } // move the node to the target parent, which may or may not be the original parent - ChildAssociationRef newChildAssocRef = moveNode( - archivedNodeRef, - destinationParentNodeRef, - assocTypeQName, - assocQName); + ChildAssociationRef newChildAssocRef = moveNode(archivedNodeRef, destinationParentNodeRef, assocTypeQName, assocQName); archivedNodeRef = newChildAssocRef.getChildRef(); archivedNodeStatus = nodeDaoService.getNodeStatus(archivedNodeRef, false); @@ -2113,17 +2086,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node restoreNode = restoreNodeStatus.getNode(); restoreAssocs(restoreNode, propQNameEntityOrigParentAssoc); } - + // the node reference has changed due to the store move NodeRef restoredNodeRef = archivedNode.getNodeRef(); - + // done if (logger.isDebugEnabled()) { - logger.debug("Restored node: \n" + - " original noderef: " + archivedNodeRef + "\n" + - " restored noderef: " + restoredNodeRef + "\n" + - " new parent: " + destinationParentNodeRef); + logger.debug("Restored node: \n" + + " original noderef: " + archivedNodeRef + "\n" + " restored noderef: " + restoredNodeRef + "\n" + " new parent: " + destinationParentNodeRef); } return restoredNodeRef; } @@ -2135,9 +2106,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Map properties = node.getProperties(); // restore parent associations - Collection parentAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); + Collection parentAssocRefs = (Collection) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); if (parentAssocRefs != null) { for (ChildAssociationRef assocRef : parentAssocRefs) @@ -2150,23 +2119,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node parentNode = getNodeNotNull(parentNodeRef); // get the name to use for the unique child check QName assocTypeQName = assocRef.getTypeQName(); - nodeDaoService.newChildAssoc( - parentNode, - node, - assocRef.isPrimary(), - assocTypeQName, - assocRef.getQName()); + nodeDaoService.newChildAssoc(parentNode, node, assocRef.isPrimary(), assocTypeQName, assocRef.getQName()); } properties.remove(propQNameEntityOrigParentAssoc.getId()); } - + // make sure that the node name uniqueness is enforced setChildUniqueName(node); - + // restore child associations - Collection childAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); + Collection childAssocRefs = (Collection) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); if (childAssocRefs != null) { for (ChildAssociationRef assocRef : childAssocRefs) @@ -2179,21 +2141,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Node childNode = getNodeNotNull(childNodeRef); QName assocTypeQName = assocRef.getTypeQName(); // get the name to use for the unique child check - nodeDaoService.newChildAssoc( - node, - childNode, - assocRef.isPrimary(), - assocTypeQName, - assocRef.getQName()); + nodeDaoService.newChildAssoc(node, childNode, assocRef.isPrimary(), assocTypeQName, assocRef.getQName()); // ensure that the name uniqueness is enforced for the child node setChildUniqueName(childNode); } properties.remove(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); } // restore source associations - Collection sourceAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); + Collection sourceAssocRefs = (Collection) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); if (sourceAssocRefs != null) { for (AssociationRef assocRef : sourceAssocRefs) @@ -2209,9 +2164,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl properties.remove(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); } // restore target associations - Collection targetAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); + Collection targetAssocRefs = (Collection) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); if (targetAssocRefs != null) { for (AssociationRef assocRef : targetAssocRefs) @@ -2229,12 +2182,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // remove the aspect node.getAspects().remove(ContentModel.ASPECT_ARCHIVED_ASSOCS); } - + /** * Checks the dictionary's definition of the association to assign a unique name to the child node. * - * @param assocTypeQName the type of the child association - * @param childNode the child node being added. The name will be extracted from it, if necessary. + * @param assocTypeQName + * the type of the child association + * @param childNode + * the child node being added. The name will be extracted from it, if necessary. * @return Returns the value to be put on the child association for uniqueness, or null if */ private void setChildUniqueName(Node childNode) @@ -2277,9 +2232,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // done if (logger.isDebugEnabled()) { - logger.debug( - "Unique name set for all " + parentAssocs.size() + " parent associations: \n" + - " name: " + useName); + logger.debug("Unique name set for all " + parentAssocs.size() + " parent associations: \n" + " name: " + useName); } } }