use of org.alfresco.service.cmr.repository.CyclicChildRelationshipException in project alfresco-repository by Alfresco.
the class BaseNodeServiceTest method testGetPaths.
/**
* @see #buildNodeGraph()
*/
@Test
public void testGetPaths() throws Exception {
Map<QName, ChildAssociationRef> assocRefs = buildNodeGraph();
NodeRef n1Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "root_p_n1")).getChildRef();
NodeRef n6Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n3_p_n6")).getChildRef();
NodeRef n8Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n6_p_n8")).getChildRef();
// get all paths for the root node
Collection<Path> paths = nodeService.getPaths(rootNodeRef, false);
assertEquals("Root node must have exactly 1 path", 1, paths.size());
Path rootPath = paths.toArray(new Path[1])[0];
assertNotNull("Root node path must have 1 element", rootPath.last());
assertEquals("Root node path must have 1 element", rootPath.first(), rootPath.last());
// get all paths for n8
paths = nodeService.getPaths(n8Ref, false);
// n6 is a root as well
assertEquals("Incorrect path count", 6, paths.size());
// check that each path element has parent node ref, qname and child node ref
for (Path path : paths) {
// get the path elements
for (Path.Element element : path) {
assertTrue("Path element of incorrect type", element instanceof Path.ChildAssocElement);
Path.ChildAssocElement childAssocElement = (Path.ChildAssocElement) element;
ChildAssociationRef ref = childAssocElement.getRef();
if (childAssocElement != path.first()) {
// for all but the first element, the parent and assoc qname must be set
assertNotNull("Parent node ref not set", ref.getParentRef());
assertNotNull("QName not set", ref.getQName());
}
// all associations must have a child ref
assertNotNull("Child node ref not set", ref.getChildRef());
}
}
// get primary path for n8
paths = nodeService.getPaths(n8Ref, true);
assertEquals("Incorrect path count", 1, paths.size());
// check that a cyclic path is detected - make n6_n1
try {
nodeService.addChild(n6Ref, n1Ref, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("n6_n1"));
nodeService.getPaths(n6Ref, false);
fail("Cyclic relationship not detected");
} catch (CyclicChildRelationshipException e) {
// expected
} catch (StackOverflowError e) {
throw e;
}
}
use of org.alfresco.service.cmr.repository.CyclicChildRelationshipException in project alfresco-repository by Alfresco.
the class BaseNodeServiceTest method testAddChild.
@Test
public void testAddChild() throws Exception {
NodeRef childNodeRef1 = nodeService.createNode(rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("C1"), ContentModel.TYPE_CONTAINER).getChildRef();
int count = countChildrenOfNode(rootNodeRef);
assertEquals("Root children count incorrect", 1, count);
NodeRef childNodeRef2 = nodeService.createNode(childNodeRef1, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("C2"), ContentModel.TYPE_CONTAINER).getChildRef();
count = countChildrenOfNode(rootNodeRef);
assertEquals("Root children count incorrect", 1, count);
// associate the two nodes
nodeService.addChild(rootNodeRef, childNodeRef2, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("pathB"));
// there should now be 2 child assocs on the root
int countAfter = countChildrenOfNode(rootNodeRef);
assertEquals("Root children count incorrect", 2, countAfter);
// now attempt to create a cyclical relationship
try {
nodeService.addChild(childNodeRef1, rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, QName.createQName("backToRoot"));
fail("Failed to detect cyclic child relationship during addition of child");
} catch (CyclicChildRelationshipException e) {
// expected
}
}
use of org.alfresco.service.cmr.repository.CyclicChildRelationshipException in project alfresco-repository by Alfresco.
the class AbstractNodeDAOImpl method prependPaths.
/**
* Build the paths for a node
*
* @param currentNodePair the leave or child node to start with
* @param currentRootNodePair pass in <tt>null</tt> only
* @param currentPath an empty {@link Path}
* @param completedPaths completed paths i.e. the result
* @param assocIdStack a stack to detected cyclic relationships
* @param primaryOnly <tt>true</tt> to follow only primary parent associations
* @throws CyclicChildRelationshipException
*/
private void prependPaths(Pair<Long, NodeRef> currentNodePair, Pair<StoreRef, NodeRef> currentRootNodePair, Path currentPath, Collection<Path> completedPaths, Stack<Long> assocIdStack, boolean primaryOnly) throws CyclicChildRelationshipException {
if (isDebugEnabled) {
logger.debug("\n" + "Prepending paths: \n" + " Current node: " + currentNodePair + "\n" + " Current root: " + currentRootNodePair + "\n" + " Current path: " + currentPath);
}
Long currentNodeId = currentNodePair.getFirst();
NodeRef currentNodeRef = currentNodePair.getSecond();
// Check if we have changed root nodes
StoreRef currentStoreRef = currentNodeRef.getStoreRef();
if (currentRootNodePair == null || !currentStoreRef.equals(currentRootNodePair.getFirst())) {
// We've changed stores
Pair<Long, NodeRef> rootNodePair = getRootNode(currentStoreRef);
currentRootNodePair = new Pair<StoreRef, NodeRef>(currentStoreRef, rootNodePair.getSecond());
}
// get the parent associations of the given node
// note: currently may throw NotLiveNodeException
ParentAssocsInfo parentAssocInfo = getParentAssocsCached(currentNodeId);
// bulk load parents as we are certain to hit them in the next call
ArrayList<Long> toLoad = new ArrayList<Long>(parentAssocInfo.getParentAssocs().size());
for (Map.Entry<Long, ChildAssocEntity> entry : parentAssocInfo.getParentAssocs().entrySet()) {
toLoad.add(entry.getValue().getParentNode().getId());
}
cacheNodesById(toLoad);
// does the node have parents
boolean hasParents = parentAssocInfo.getParentAssocs().size() > 0;
// look for a root. If we only want the primary root, then ignore all but the top-level root.
if (// exclude primary search with parents present
!(primaryOnly && hasParents) && parentAssocInfo.isRoot()) {
// 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, currentRootNodePair.getSecond());
// create a path to save and add the 'root' assoc
Path pathToSave = new Path();
Path.ChildAssocElement first = null;
for (Path.Element element : currentPath) {
if (first == null) {
first = (Path.ChildAssocElement) element;
} else {
pathToSave.append(element);
}
}
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(parentAssocInfo.isStoreRoot() ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), currentRootNodePair.getSecond(), 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);
}
// walk up each parent association
for (Map.Entry<Long, ChildAssocEntity> entry : parentAssocInfo.getParentAssocs().entrySet()) {
Long assocId = entry.getKey();
ChildAssocEntity assoc = entry.getValue();
ChildAssociationRef assocRef = assoc.getRef(qnameDAO);
// do we consider only primary assocs?
if (primaryOnly && !assocRef.isPrimary()) {
continue;
}
// Ordering is meaningless here as we are constructing a path upwards
// and have no idea where the node comes in the sibling order or even
// if there are like-pathed siblings.
assocRef.setNthSibling(-1);
// build a path element
Path.Element element = new Path.ChildAssocElement(assocRef);
// create a new path that builds on the current path
Path path = new Path();
path.append(currentPath);
// prepend element
path.prepend(element);
// get parent node pair
Pair<Long, NodeRef> parentNodePair = new Pair<Long, NodeRef>(assoc.getParentNode().getId(), assocRef.getParentRef());
// does the association already exist in the stack
if (assocIdStack.contains(assocId)) {
// the association was present already
logger.error("Cyclic parent-child relationship detected: \n" + " current node: " + currentNodeId + "\n" + " current path: " + currentPath + "\n" + " next assoc: " + assocId);
throw new CyclicChildRelationshipException("Node has been pasted into its own tree.", assocRef);
}
if (isDebugEnabled) {
logger.debug("\n" + " Prepending path parent: \n" + " Parent node: " + parentNodePair);
}
// push the assoc stack, recurse and pop
assocIdStack.push(assocId);
prependPaths(parentNodePair, currentRootNodePair, path, completedPaths, assocIdStack, primaryOnly);
assocIdStack.pop();
}
// done
}
use of org.alfresco.service.cmr.repository.CyclicChildRelationshipException in project alfresco-repository by Alfresco.
the class RuleServiceImplTest method testCyclicGraphWithInheritedRules.
/**
* Ensure that the rule store can cope with a cyclic node graph
*
* @throws Exception
*/
@Test
public void testCyclicGraphWithInheritedRules() throws Exception {
NodeRef nodeRef1 = createNewNode(this.rootNodeRef);
NodeRef nodeRef2 = createNewNode(nodeRef1);
NodeRef nodeRef3 = createNewNode(nodeRef2);
try {
this.nodeService.addChild(nodeRef3, nodeRef1, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}loop"));
fail("Expected detection of cyclic relationship");
} catch (CyclicChildRelationshipException e) {
// expected
// the node will still have been created in the current transaction, although the txn will be rollback-only
}
Rule rule1 = createTestRule(true);
this.ruleService.saveRule(nodeRef1, rule1);
Rule rule2 = createTestRule(true);
this.ruleService.saveRule(nodeRef2, rule2);
Rule rule3 = createTestRule(true);
this.ruleService.saveRule(nodeRef3, rule3);
List<? extends Rule> allRules1 = this.ruleService.getRules(nodeRef1, true);
assertNotNull(allRules1);
assertEquals(3, allRules1.size());
assertTrue(allRules1.contains(rule1));
assertTrue(allRules1.contains(rule2));
assertTrue(allRules1.contains(rule3));
List<? extends Rule> allRules2 = this.ruleService.getRules(nodeRef2, true);
assertNotNull(allRules2);
assertEquals(3, allRules2.size());
assertTrue(allRules2.contains(rule1));
assertTrue(allRules2.contains(rule2));
assertTrue(allRules2.contains(rule3));
List<? extends Rule> allRules3 = this.ruleService.getRules(nodeRef3, true);
assertNotNull(allRules3);
assertEquals(3, allRules3.size());
assertTrue(allRules3.contains(rule1));
assertTrue(allRules3.contains(rule2));
assertTrue(allRules3.contains(rule3));
}
use of org.alfresco.service.cmr.repository.CyclicChildRelationshipException in project alfresco-repository by Alfresco.
the class FileFolderServiceImplTest method testETHREEOH_3088_MoveIntoSelf.
public void testETHREEOH_3088_MoveIntoSelf() throws Exception {
FileInfo folderInfo = fileFolderService.create(workingRootNodeRef, "NotGood.txt", ContentModel.TYPE_FOLDER);
NodeRef folderNodeRef = folderInfo.getNodeRef();
// Move into self
try {
fileFolderService.move(folderNodeRef, folderNodeRef, null);
fail("Failed to detect cyclic relationship");
} catch (CyclicChildRelationshipException e) {
// Expected
}
}
Aggregations