Fix ups for null permissions

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9988 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrew Hind 2008-07-23 11:32:12 +00:00
parent ec903f2dc1
commit 08a552304e

View File

@ -99,13 +99,19 @@ import org.springframework.util.Assert;
public class DbNodeServiceImpl extends AbstractNodeServiceImpl public class DbNodeServiceImpl extends AbstractNodeServiceImpl
{ {
private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class); private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class);
private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths"); private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths");
private QNameDAO qnameDAO; private QNameDAO qnameDAO;
private NodeDaoService nodeDaoService; private NodeDaoService nodeDaoService;
private StoreArchiveMap storeArchiveMap; private StoreArchiveMap storeArchiveMap;
private NodeService avmNodeService; private NodeService avmNodeService;
private TenantService tenantService; private TenantService tenantService;
private AclDaoComponent aclDaoComponent; private AclDaoComponent aclDaoComponent;
public DbNodeServiceImpl() public DbNodeServiceImpl()
@ -149,9 +155,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Performs a null-safe get of the node * 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) * @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 private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException
{ {
@ -167,9 +175,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Gets the node status for a live node. * 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 <tt>null</tt> and will have a live node attached. * @return Returns the node status, which will not be <tt>null</tt> 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 public NodeStatus getNodeStatusNotNull(NodeRef nodeRef) throws InvalidNodeRefException
{ {
@ -212,9 +223,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
else else
{ {
return new NodeRef.Status( return new NodeRef.Status(nodeStatus.getTransaction().getChangeTxnId(), nodeStatus.isDeleted());
nodeStatus.getTransaction().getChangeTxnId(),
nodeStatus.isDeleted());
} }
} }
@ -234,7 +243,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
{ {
String currentUser = AuthenticationUtil.getCurrentUserName(); String currentUser = AuthenticationUtil.getCurrentUserName();
// MT: return tenant stores only (although for super System return all stores - as used by ConfigurationChecker, IndexRecovery, IndexBackup etc) // 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()))) if ((currentUser == null) || (!currentUser.equals(AuthenticationUtil.getSystemUserName())))
{ {
tenantService.checkDomain(storeRef.getIdentifier()); tenantService.checkDomain(storeRef.getIdentifier());
@ -258,6 +268,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Defers to the typed service * Defers to the typed service
*
* @see StoreDaoService#createWorkspace(String) * @see StoreDaoService#createWorkspace(String)
*/ */
public StoreRef createStore(String protocol, String identifier) public StoreRef createStore(String protocol, String identifier)
@ -281,9 +292,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
NodeRef rootNodeRef = tenantService.getBaseName(rootNode.getNodeRef()); NodeRef rootNodeRef = tenantService.getBaseName(rootNode.getNodeRef());
// assign the root aspect - this is expected of all roots, even store roots // assign the root aspect - this is expected of all roots, even store roots
addAspect(rootNodeRef, addAspect(rootNodeRef, ContentModel.ASPECT_ROOT, Collections.<QName, Serializable> emptyMap());
ContentModel.ASPECT_ROOT,
Collections.<QName, Serializable>emptyMap());
// Bind root permission // Bind root permission
@ -352,24 +361,17 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* @see #createNode(NodeRef, QName, QName, QName, Map) * @see #createNode(NodeRef, QName, QName, QName, Map)
*/ */
public ChildAssociationRef createNode( public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName, QName nodeTypeQName)
NodeRef parentRef,
QName assocTypeQName,
QName assocQName,
QName nodeTypeQName)
{ {
return this.createNode(parentRef, assocTypeQName, assocQName, nodeTypeQName, null); 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( public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName, QName nodeTypeQName, Map<QName, Serializable> properties)
NodeRef parentRef,
QName assocTypeQName,
QName assocQName,
QName nodeTypeQName,
Map<QName, Serializable> properties)
{ {
Assert.notNull(parentRef); Assert.notNull(parentRef);
Assert.notNull(assocTypeQName); Assert.notNull(assocTypeQName);
@ -417,12 +419,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
invokeBeforeCreateChildAssociation(parentRef, childNodeRef, assocTypeQName, assocQName, true); invokeBeforeCreateChildAssociation(parentRef, childNodeRef, assocTypeQName, assocQName, true);
// Create the association // Create the association
ChildAssoc childAssoc = nodeDaoService.newChildAssoc( ChildAssoc childAssoc = nodeDaoService.newChildAssoc(parentNode, childNode, true, assocTypeQName, assocQName);
parentNode,
childNode,
true,
assocTypeQName,
assocQName);
// Set the default property values // Set the default property values
addDefaultPropertyValues(nodeTypeDef, properties); addDefaultPropertyValues(nodeTypeDef, properties);
@ -499,12 +496,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Drops the old primary association and creates a new one * Drops the old primary association and creates a new one
*/ */
public ChildAssociationRef moveNode( public ChildAssociationRef moveNode(NodeRef nodeToMoveRef, NodeRef newParentRef, QName assocTypeQName, QName assocQName) throws InvalidNodeRefException
NodeRef nodeToMoveRef,
NodeRef newParentRef,
QName assocTypeQName,
QName assocQName)
throws InvalidNodeRefException
{ {
Assert.notNull(nodeToMoveRef); Assert.notNull(nodeToMoveRef);
Assert.notNull(newParentRef); Assert.notNull(newParentRef);
@ -541,12 +533,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
nodeDaoService.deleteChildAssoc(oldAssoc, false); nodeDaoService.deleteChildAssoc(oldAssoc, false);
// create a new assoc // create a new assoc
ChildAssoc newAssoc = nodeDaoService.newChildAssoc( ChildAssoc newAssoc = nodeDaoService.newChildAssoc(newParentNode, nodeToMove, true, assocTypeQName, assocQName);
newParentNode,
nodeToMove,
true,
assocTypeQName,
assocQName);
setChildUniqueName(nodeToMove); // ensure uniqueness setChildUniqueName(nodeToMove); // ensure uniqueness
ChildAssociationRef newAssocRef = tenantService.getBaseName(newAssoc.getChildAssocRef()); ChildAssociationRef newAssocRef = tenantService.getBaseName(newAssoc.getChildAssocRef());
@ -566,11 +553,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// Fix inherited permissions // Fix inherited permissions
if (aclDaoComponent != null) if (aclDaoComponent != null)
{
if (newAssoc.getChild().getAccessControlList() != null)
{ {
Long targetAcl = newAssoc.getChild().getAccessControlList().getId(); Long targetAcl = newAssoc.getChild().getAccessControlList().getId();
AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAcl); AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAcl);
Boolean inherits = aclProperties.getInherits(); Boolean inherits = aclProperties.getInherits();
if ((inherits != null) && (inherits.booleanValue())) if ((inherits != null) && (inherits.booleanValue()))
{
if (newAssoc.getParent().getAccessControlList() != null)
{ {
Long parentAcl = newAssoc.getParent().getAccessControlList().getId(); Long parentAcl = newAssoc.getParent().getAccessControlList().getId();
Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl); Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl);
@ -583,6 +574,33 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
DMAccessControlListDAO.setFixedAcls(newAssoc.getChildAssocRef().getChildRef(), inheritedAcl, true, this, aclDaoComponent, nodeDaoService); 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);
}
}
} }
@ -596,7 +614,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
nodeToMoveAspectQNames.add(nodeToMoveAspectQName); nodeToMoveAspectQNames.add(nodeToMoveAspectQName);
} }
// TODO for now indicate that the node has been archived to prevent the version history from being removed // 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); invokeOnDeleteNode(oldAssocRef, nodeToMoveTypeQName, nodeToMoveAspectQNames, true);
invokeOnCreateNode(newAssoc.getChildAssocRef()); invokeOnCreateNode(newAssoc.getChildAssocRef());
} }
@ -620,17 +639,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
Node parentNode = getNodeNotNull(childAssocRef.getParentRef()); Node parentNode = getNodeNotNull(childAssocRef.getParentRef());
Node childNode = getNodeNotNull(childAssocRef.getChildRef()); Node childNode = getNodeNotNull(childAssocRef.getChildRef());
ChildAssoc assoc = nodeDaoService.getChildAssoc( ChildAssoc assoc = nodeDaoService.getChildAssoc(parentNode, childNode, childAssocRef.getTypeQName(), childAssocRef.getQName());
parentNode,
childNode,
childAssocRef.getTypeQName(),
childAssocRef.getQName());
if (assoc == null) if (assoc == null)
{ {
throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + " assoc: " + childAssocRef + "\n" + " index: " + index, childAssocRef);
" assoc: " + childAssocRef + "\n" +
" index: " + index,
childAssocRef);
} }
// set the index // set the index
assoc.setIndex(index); assoc.setIndex(index);
@ -645,7 +657,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* @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 public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException
{ {
@ -677,11 +690,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* @see Node#getAspects() * @see Node#getAspects()
*/ */
public void addAspect( public void addAspect(NodeRef nodeRef, QName aspectTypeQName, Map<QName, Serializable> aspectProperties) throws InvalidNodeRefException, InvalidAspectException
NodeRef nodeRef,
QName aspectTypeQName,
Map<QName, Serializable> aspectProperties)
throws InvalidNodeRefException, InvalidAspectException
{ {
// check that the aspect is legal // check that the aspect is legal
AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName);
@ -730,8 +739,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* @see Node#getAspects() * @see Node#getAspects()
*/ */
public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) throws InvalidNodeRefException, InvalidAspectException
throws InvalidNodeRefException, InvalidAspectException
{ {
// get the aspect // get the aspect
AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName);
@ -862,8 +870,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// check if we need to archive the node // check if we need to archive the node
StoreRef archiveStoreRef = null; StoreRef archiveStoreRef = null;
if (nodeAspectQNameEntityIds.contains(aspectTempQNameEntity.getId()) || if (nodeAspectQNameEntityIds.contains(aspectTempQNameEntity.getId()) || nodeAspectQNameEntityIds.contains(aspectWorkingCopyQNameEntity.getId()))
nodeAspectQNameEntityIds.contains(aspectWorkingCopyQNameEntity.getId()))
{ {
// The node is either temporary or a working copy. // The node is either temporary or a working copy.
// It can not be archived. // It can not be archived.
@ -916,12 +923,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName, false); invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName, false);
// make the association // make the association
ChildAssoc assoc = nodeDaoService.newChildAssoc( ChildAssoc assoc = nodeDaoService.newChildAssoc(parentNode, childNode, false, assocTypeQName, assocQName);
parentNode,
childNode,
false,
assocTypeQName,
assocQName);
// ensure name uniqueness // ensure name uniqueness
setChildUniqueName(childNode); setChildUniqueName(childNode);
ChildAssociationRef assocRef = assoc.getChildAssocRef(); ChildAssociationRef assocRef = assoc.getChildAssocRef();
@ -1019,9 +1021,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
if (assoc.getIsPrimary()) if (assoc.getIsPrimary())
{ {
throw new IllegalArgumentException( throw new IllegalArgumentException("removeSeconaryChildAssociation can not be applied to a primary association: \n" + " Child Assoc: " + assoc);
"removeSeconaryChildAssociation can not be applied to a primary association: \n" +
" Child Assoc: " + assoc);
} }
// Delete the secondary association // Delete the secondary association
nodeDaoService.deleteChildAssoc(assoc, false); 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 * Remove properties that should not be persisted as general properties. Where necessary, the properties are set on
* properties are set on the node. * the node.
* *
* @param node the node to set properties on * @param node
* @param properties properties to change * the node to set properties on
* @param properties
* properties to change
*/ */
private void extractIntrinsicProperties(Node node, Map<QName, Serializable> properties) private void extractIntrinsicProperties(Node node, Map<QName, Serializable> properties)
{ {
@ -1048,18 +1050,19 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Adds all properties used by the * Adds all properties used by the {@link ContentModel#ASPECT_REFERENCEABLE referencable aspect}.
* {@link ContentModel#ASPECT_REFERENCEABLE referencable aspect}.
* <p> * <p>
* This method can be used to ensure that the values used by the aspect * This method can be used to ensure that the values used by the aspect are present as node properties.
* are present as node properties.
* <p> * <p>
* This method also ensures that the {@link ContentModel#PROP_NAME name property} * This method also ensures that the {@link ContentModel#PROP_NAME name property} is always present as a property on
* is always present as a property on a node. * a node.
* *
* @param node the node with the values * @param node
* @param nodeRef the node reference containing the values required * the node with the values
* @param properties the node properties * @param nodeRef
* the node reference containing the values required
* @param properties
* the node properties
*/ */
private void addIntrinsicProperties(Node node, Map<QName, Serializable> properties) private void addIntrinsicProperties(Node node, Map<QName, Serializable> properties)
{ {
@ -1159,14 +1162,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Ensures that all required properties are present on the node and copies the * Ensures that all required properties are present on the node and copies the property values to the
* property values to the <code>Node</code>. * <code>Node</code>.
* <p> * <p>
* To remove a property, <b>remove it from the map</b> before calling this method. * To remove a property, <b>remove it from the map</b> before calling this method. Null-valued properties are
* Null-valued properties are allowed. * allowed.
* <p> * <p>
* If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into * If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into a real
* a real nulls when the properties are requested again. * nulls when the properties are requested again.
* *
* @see Node#getProperties() * @see Node#getProperties()
*/ */
@ -1192,8 +1195,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
* 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. * operation is complete.
* *
* @param node the node * @param node
* @param properties the map of property values * the node
* @param properties
* the map of property values
* @return the map of property values after the set operation is complete * @return the map of property values after the set operation is complete
* @throws InvalidNodeRefException * @throws InvalidNodeRefException
*/ */
@ -1229,8 +1234,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Gets the properties map, sets the value (null is allowed) and checks that the new set * Gets the properties map, sets the value (null is allowed) and checks that the new set of properties is valid.
* of properties is valid.
* *
* @see DbNodeServiceImpl.NullPropertyValue * @see DbNodeServiceImpl.NullPropertyValue
*/ */
@ -1262,9 +1266,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
* 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. * complete.
* *
* @param node the node * @param node
* @param qname the qname of the property * the node
* @param value the value of the property * @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 * @return the values of the properties after the set operation is complete
* @throws InvalidNodeRefException * @throws InvalidNodeRefException
*/ */
@ -1459,8 +1466,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
return assocRef; return assocRef;
} }
public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) throws InvalidNodeRefException, AssociationExistsException
throws InvalidNodeRefException, AssociationExistsException
{ {
Node sourceNode = getNodeNotNull(sourceRef); Node sourceNode = getNodeNotNull(sourceRef);
Node targetNode = getNodeNotNull(targetRef); Node targetNode = getNodeNotNull(targetRef);
@ -1480,8 +1486,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
return assocRef; return assocRef;
} }
public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) throws InvalidNodeRefException
throws InvalidNodeRefException
{ {
Node sourceNode = getNodeNotNull(sourceRef); Node sourceNode = getNodeNotNull(sourceRef);
Node targetNode = getNodeNotNull(targetRef); Node targetNode = getNodeNotNull(targetRef);
@ -1544,25 +1549,24 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Recursive method used to build up paths from a given node to the root. * Recursive method used to build up paths from a given node to the root.
* <p> * <p>
* Whilst walking up the hierarchy to the root, some nodes may have a <b>root</b> aspect. * Whilst walking up the hierarchy to the root, some nodes may have a <b>root</b> aspect. Everytime one of these is
* Everytime one of these is encountered, a new path is farmed off, but the method * encountered, a new path is farmed off, but the method continues to walk up the hierarchy.
* continues to walk up the hierarchy.
* *
* @param currentNode the node to start from, i.e. the child node to work upwards from * @param currentNode
* @param currentPath the path from the current node to the descendent that we started from * the node to start from, i.e. the child node to work upwards from
* @param completedPaths paths that have reached the root are added to this collection * @param currentPath
* @param assocStack the parent-child relationships traversed whilst building the path. * the path from the current node to the descendent that we started from
* Used to detected cyclic relationships. * @param completedPaths
* @param primaryOnly true if only the primary parent association must be traversed. * paths that have reached the root are added to this collection
* If this is true, then the only root is the top level node having no parents. * @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 * @throws CyclicChildRelationshipException
*/ */
private void prependPaths( private void prependPaths(final Node currentNode, final Path currentPath, Collection<Path> completedPaths, Stack<ChildAssoc> assocStack, boolean primaryOnly)
final Node currentNode,
final Path currentPath,
Collection<Path> completedPaths,
Stack<ChildAssoc> assocStack,
boolean primaryOnly)
throws CyclicChildRelationshipException throws CyclicChildRelationshipException
{ {
NodeRef currentNodeRef = currentNode.getNodeRef(); NodeRef currentNodeRef = currentNode.getNodeRef();
@ -1581,11 +1585,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// this effectively spoofs the fact that the current node is not below the root // 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 // - we put this assoc in as the first assoc in the path must be a one-sided
// reference pointing to the root node // reference pointing to the root node
ChildAssociationRef assocRef = new ChildAssociationRef( ChildAssociationRef assocRef = new ChildAssociationRef(null, null, null, getRootNode(currentNode.getNodeRef().getStoreRef()));
null,
null,
null,
getRootNode(currentNode.getNodeRef().getStoreRef()));
// create a path to save and add the 'root' assoc // create a path to save and add the 'root' assoc
Path pathToSave = new Path(); Path pathToSave = new Path();
Path.ChildAssocElement first = null; Path.ChildAssocElement first = null;
@ -1604,11 +1604,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
{ {
// mimic an association that would appear if the current node was below the root node // 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 // or if first beneath the root node it will make the real thing
ChildAssociationRef updateAssocRef = new ChildAssociationRef( ChildAssociationRef updateAssocRef = new ChildAssociationRef(isStoreRoot ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), getRootNode(currentNode
isStoreRoot ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), .getNodeRef().getStoreRef()), first.getRef().getQName(), first.getRef().getChildRef());
getRootNode(currentNode.getNodeRef().getStoreRef()),
first.getRef().getQName(),
first.getRef().getChildRef());
Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef); Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef);
pathToSave.prepend(newFirst); pathToSave.prepend(newFirst);
} }
@ -1622,8 +1619,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
if (parentAssocs.size() == 0 && !isRoot) if (parentAssocs.size() == 0 && !isRoot)
{ {
throw new RuntimeException("Node without parents does not have root aspect: " + throw new RuntimeException("Node without parents does not have root aspect: " + currentNodeRef);
currentNodeRef);
} }
// walk up each parent association // walk up each parent association
for (ChildAssoc assoc : parentAssocs) for (ChildAssoc assoc : parentAssocs)
@ -1632,12 +1628,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
if (assocStack.contains(assoc)) if (assocStack.contains(assoc))
{ {
// the association was present already // the association was present already
throw new CyclicChildRelationshipException( throw new CyclicChildRelationshipException("Cyclic parent-child relationship detected: \n"
"Cyclic parent-child relationship detected: \n" + + " current node: " + currentNode + "\n" + " current path: " + currentPath + "\n" + " next assoc: " + assoc, assoc);
" current node: " + currentNode + "\n" +
" current path: " + currentPath + "\n" +
" next assoc: " + assoc,
assoc);
} }
// do we consider only primary assocs? // do we consider only primary assocs?
if (primaryOnly && !assoc.getIsPrimary()) if (primaryOnly && !assoc.getIsPrimary())
@ -1650,13 +1642,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
NodeRef childRef = tenantService.getBaseName(assoc.getChild().getNodeRef()); NodeRef childRef = tenantService.getBaseName(assoc.getChild().getNodeRef());
boolean isPrimary = assoc.getIsPrimary(); boolean isPrimary = assoc.getIsPrimary();
// build a real association reference // build a real association reference
ChildAssociationRef assocRef = new ChildAssociationRef( ChildAssociationRef assocRef = new ChildAssociationRef(assoc.getTypeQName().getQName(), parentRef, qname, childRef, isPrimary, -1);
assoc.getTypeQName().getQName(),
parentRef,
qname,
childRef,
isPrimary,
-1);
// Ordering is not important here: We are building distinct paths upwards // Ordering is not important here: We are building distinct paths upwards
Path.Element element = new Path.ChildAssocElement(assocRef); Path.Element element = new Path.ChildAssocElement(assocRef);
// create a new path that builds on the current path // create a new path that builds on the current path
@ -1690,8 +1676,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* When searching for <code>primaryOnly == true</code>, checks that there is exactly * When searching for <code>primaryOnly == true</code>, checks that there is exactly one path.
* one path. *
* @see #prependPaths(Node, Path, Collection, Stack, boolean) * @see #prependPaths(Node, Path, Collection, Stack, boolean)
*/ */
public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException
@ -1752,44 +1738,31 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
Set<Long> aspects = node.getAspects(); Set<Long> aspects = node.getAspects();
aspects.add(aspectQNameEntityArchived.getId()); aspects.add(aspectQNameEntityArchived.getId());
Map<Long, PropertyValue> properties = node.getProperties(); Map<Long, PropertyValue> properties = node.getProperties();
PropertyValue archivedByProperty = makePropertyValue( PropertyValue archivedByProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY), AuthenticationUtil.getCurrentUserName());
dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY),
AuthenticationUtil.getCurrentUserName());
properties.put(propQNameArchivedBy.getId(), archivedByProperty); properties.put(propQNameArchivedBy.getId(), archivedByProperty);
PropertyValue archivedDateProperty = makePropertyValue( PropertyValue archivedDateProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE), new Date());
dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE),
new Date());
properties.put(propQNameArchivedDate.getId(), archivedDateProperty); properties.put(propQNameArchivedDate.getId(), archivedDateProperty);
PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue( PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), primaryParentAssoc
dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), .getChildAssocRef());
primaryParentAssoc.getChildAssocRef());
properties.put(propQNameArchivedOriginalParentAssoc.getId(), archivedPrimaryParentNodeRefProperty); properties.put(propQNameArchivedOriginalParentAssoc.getId(), archivedPrimaryParentNodeRefProperty);
PropertyValue originalOwnerProperty = properties.get(propQNameEntityOwner.getId()); PropertyValue originalOwnerProperty = properties.get(propQNameEntityOwner.getId());
PropertyValue originalCreatorProperty = properties.get(propQNameEntityCreator.getId()); PropertyValue originalCreatorProperty = properties.get(propQNameEntityCreator.getId());
if (originalOwnerProperty != null || originalCreatorProperty != null) if (originalOwnerProperty != null || originalCreatorProperty != null)
{ {
QNameEntity propQNameArchivedOriginalOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); QNameEntity propQNameArchivedOriginalOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER);
properties.put( properties.put(propQNameArchivedOriginalOwner.getId(), originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty);
propQNameArchivedOriginalOwner.getId(),
originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty);
} }
// change the node ownership // change the node ownership
QNameEntity ownableAspectQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_OWNABLE); QNameEntity ownableAspectQNameEntity = qnameDAO.getOrCreateQNameEntity(ContentModel.ASPECT_OWNABLE);
aspects.add(ownableAspectQNameEntity.getId()); aspects.add(ownableAspectQNameEntity.getId());
PropertyValue newOwnerProperty = makePropertyValue( PropertyValue newOwnerProperty = makePropertyValue(dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER), AuthenticationUtil.getCurrentUserName());
dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER),
AuthenticationUtil.getCurrentUserName());
QNameEntity propQNameOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_OWNER); QNameEntity propQNameOwner = qnameDAO.getOrCreateQNameEntity(ContentModel.PROP_OWNER);
properties.put(propQNameOwner.getId(), newOwnerProperty); properties.put(propQNameOwner.getId(), newOwnerProperty);
// move the node // move the node
NodeRef archiveStoreRootNodeRef = getRootNode(archiveStoreRef); NodeRef archiveStoreRootNodeRef = getRootNode(archiveStoreRef);
moveNode( moveNode(nodeRef, archiveStoreRootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem"));
nodeRef,
archiveStoreRootNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem"));
// the node reference has changed due to the store move // the node reference has changed due to the store move
nodeRef = node.getNodeRef(); nodeRef = node.getNodeRef();
@ -1812,12 +1785,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Performs all the necessary housekeeping involved in changing a node's store. * Performs all the necessary housekeeping involved in changing a node's store. This method cascades down through
* This method cascades down through all the primary children of the node as * all the primary children of the node as well.
* well.
* *
* @param node the node whose store is changing * @param node
* @param store the new store for the node * the node whose store is changing
* @param store
* the new store for the node
*/ */
private void moveNodeToStore(Node node, Store store) private void moveNodeToStore(Node node, Store store)
{ {
@ -1867,12 +1841,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Fill the map of all primary children below the given node. * Fill the map of all primary children below the given node. The given node will be added to the map and the method
* The given node will be added to the map and the method is recursive * is recursive to all primary children.
* to all primary children.
* *
* @param nodeStatus the status of the node at the top of the hierarchy * @param nodeStatus
* @param nodeStatusesById a map of node statuses that will be reused as the return value * 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 * @return Returns a map of nodes in the hierarchy keyed by their IDs
*/ */
private Map<Long, NodeStatus> getNodeHierarchy(NodeStatus nodeStatus, Map<Long, NodeStatus> nodeStatusesById) private Map<Long, NodeStatus> getNodeHierarchy(NodeStatus nodeStatus, Map<Long, NodeStatus> nodeStatusesById)
@ -1910,13 +1885,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
} }
/** /**
* Archive all associations to and from the given node, with the * Archive all associations to and from the given node, with the exception of associations to or from nodes in the
* exception of associations to or from nodes in the given map. * given map.
* <p> * <p>
* Primary parent associations are also ignored. * Primary parent associations are also ignored.
* *
* @param node the node whose associations must be archived * @param node
* @param nodesById a map of nodes partaking in the archival process * the node whose associations must be archived
* @param nodesById
* a map of nodes partaking in the archival process
*/ */
private void archiveAssocs(Node node, Map<Long, NodeStatus> nodeStatusesById) private void archiveAssocs(Node node, Map<Long, NodeStatus> nodeStatusesById)
{ {
@ -2060,13 +2037,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
{ {
throw new AlfrescoRuntimeException("The node to archive is not an archive node"); throw new AlfrescoRuntimeException("The node to archive is not an archive node");
} }
ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue( ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue(dictionaryService
dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), .getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), properties.get(propQNameEntityOrigParentAssoc.getId()));
properties.get(propQNameEntityOrigParentAssoc.getId()));
PropertyValue originalOwnerProperty = properties.get(propQNameEntityOrigOwner.getId()); PropertyValue originalOwnerProperty = properties.get(propQNameEntityOrigOwner.getId());
// remove the archived aspect // 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(propQNameEntityOrigParentAssoc.getId());
properties.remove(propQNameEntityArchivedBy.getId()); properties.remove(propQNameEntityArchivedBy.getId());
@ -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 // move the node to the target parent, which may or may not be the original parent
ChildAssociationRef newChildAssocRef = moveNode( ChildAssociationRef newChildAssocRef = moveNode(archivedNodeRef, destinationParentNodeRef, assocTypeQName, assocQName);
archivedNodeRef,
destinationParentNodeRef,
assocTypeQName,
assocQName);
archivedNodeRef = newChildAssocRef.getChildRef(); archivedNodeRef = newChildAssocRef.getChildRef();
archivedNodeStatus = nodeDaoService.getNodeStatus(archivedNodeRef, false); archivedNodeStatus = nodeDaoService.getNodeStatus(archivedNodeRef, false);
@ -2120,10 +2093,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// done // done
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Restored node: \n" + logger.debug("Restored node: \n"
" original noderef: " + archivedNodeRef + "\n" + + " original noderef: " + archivedNodeRef + "\n" + " restored noderef: " + restoredNodeRef + "\n" + " new parent: " + destinationParentNodeRef);
" restored noderef: " + restoredNodeRef + "\n" +
" new parent: " + destinationParentNodeRef);
} }
return restoredNodeRef; return restoredNodeRef;
} }
@ -2135,9 +2106,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
Map<Long, PropertyValue> properties = node.getProperties(); Map<Long, PropertyValue> properties = node.getProperties();
// restore parent associations // restore parent associations
Collection<ChildAssociationRef> parentAssocRefs = (Collection<ChildAssociationRef>) getProperty( Collection<ChildAssociationRef> parentAssocRefs = (Collection<ChildAssociationRef>) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_PARENT_ASSOCS);
nodeRef,
ContentModel.PROP_ARCHIVED_PARENT_ASSOCS);
if (parentAssocRefs != null) if (parentAssocRefs != null)
{ {
for (ChildAssociationRef assocRef : parentAssocRefs) for (ChildAssociationRef assocRef : parentAssocRefs)
@ -2150,12 +2119,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
Node parentNode = getNodeNotNull(parentNodeRef); Node parentNode = getNodeNotNull(parentNodeRef);
// get the name to use for the unique child check // get the name to use for the unique child check
QName assocTypeQName = assocRef.getTypeQName(); QName assocTypeQName = assocRef.getTypeQName();
nodeDaoService.newChildAssoc( nodeDaoService.newChildAssoc(parentNode, node, assocRef.isPrimary(), assocTypeQName, assocRef.getQName());
parentNode,
node,
assocRef.isPrimary(),
assocTypeQName,
assocRef.getQName());
} }
properties.remove(propQNameEntityOrigParentAssoc.getId()); properties.remove(propQNameEntityOrigParentAssoc.getId());
} }
@ -2164,9 +2128,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
setChildUniqueName(node); setChildUniqueName(node);
// restore child associations // restore child associations
Collection<ChildAssociationRef> childAssocRefs = (Collection<ChildAssociationRef>) getProperty( Collection<ChildAssociationRef> childAssocRefs = (Collection<ChildAssociationRef>) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_CHILD_ASSOCS);
nodeRef,
ContentModel.PROP_ARCHIVED_CHILD_ASSOCS);
if (childAssocRefs != null) if (childAssocRefs != null)
{ {
for (ChildAssociationRef assocRef : childAssocRefs) for (ChildAssociationRef assocRef : childAssocRefs)
@ -2179,21 +2141,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
Node childNode = getNodeNotNull(childNodeRef); Node childNode = getNodeNotNull(childNodeRef);
QName assocTypeQName = assocRef.getTypeQName(); QName assocTypeQName = assocRef.getTypeQName();
// get the name to use for the unique child check // get the name to use for the unique child check
nodeDaoService.newChildAssoc( nodeDaoService.newChildAssoc(node, childNode, assocRef.isPrimary(), assocTypeQName, assocRef.getQName());
node,
childNode,
assocRef.isPrimary(),
assocTypeQName,
assocRef.getQName());
// ensure that the name uniqueness is enforced for the child node // ensure that the name uniqueness is enforced for the child node
setChildUniqueName(childNode); setChildUniqueName(childNode);
} }
properties.remove(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); properties.remove(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS);
} }
// restore source associations // restore source associations
Collection<AssociationRef> sourceAssocRefs = (Collection<AssociationRef>) getProperty( Collection<AssociationRef> sourceAssocRefs = (Collection<AssociationRef>) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS);
nodeRef,
ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS);
if (sourceAssocRefs != null) if (sourceAssocRefs != null)
{ {
for (AssociationRef assocRef : sourceAssocRefs) for (AssociationRef assocRef : sourceAssocRefs)
@ -2209,9 +2164,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
properties.remove(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); properties.remove(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS);
} }
// restore target associations // restore target associations
Collection<AssociationRef> targetAssocRefs = (Collection<AssociationRef>) getProperty( Collection<AssociationRef> targetAssocRefs = (Collection<AssociationRef>) getProperty(nodeRef, ContentModel.PROP_ARCHIVED_TARGET_ASSOCS);
nodeRef,
ContentModel.PROP_ARCHIVED_TARGET_ASSOCS);
if (targetAssocRefs != null) if (targetAssocRefs != null)
{ {
for (AssociationRef assocRef : targetAssocRefs) for (AssociationRef assocRef : targetAssocRefs)
@ -2233,8 +2186,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
/** /**
* Checks the dictionary's definition of the association to assign a unique name to the child node. * 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 assocTypeQName
* @param childNode the child node being added. The name will be extracted from it, if necessary. * 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 * @return Returns the value to be put on the child association for uniqueness, or null if
*/ */
private void setChildUniqueName(Node childNode) private void setChildUniqueName(Node childNode)
@ -2277,9 +2232,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// done // done
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug( logger.debug("Unique name set for all " + parentAssocs.size() + " parent associations: \n" + " name: " + useName);
"Unique name set for all " + parentAssocs.size() + " parent associations: \n" +
" name: " + useName);
} }
} }
} }