Add a check to prevent cyclic parent chains in setParent().

Only set parent for non-relational nodes in addNode() and setNode().
http://helma.org/bugs/show_bug.cgi?id=344
This commit is contained in:
hns 2004-03-09 14:25:29 +00:00
parent 2f51ace37c
commit b565d6a166

View file

@ -628,6 +628,17 @@ public final class Node implements INode, Serializable {
* the ID + DB map combo. * the ID + DB map combo.
*/ */
protected void setParent(Node parent) { protected void setParent(Node parent) {
// walk down parent node to see if we are in its parent chain.
// this is to prevent cyclic parent chains.
Node p = parent;
while (p != null) {
p = p.parentHandle == null ? null : p.parentHandle.getNode(nmgr);
if (p == this) {
// we found ourself in the argument node's parent chain -
// ignore request to make it our parent.
return;
}
}
parentHandle = (parent == null) ? null : parent.getHandle(); parentHandle = (parent == null) ? null : parent.getHandle();
} }
@ -904,7 +915,7 @@ public final class Node implements INode, Serializable {
} }
} }
if (node != this && !"root".equalsIgnoreCase(node.getPrototype())) { if (!node.isRelational() && node != this && !"root".equalsIgnoreCase(node.getPrototype())) {
// avoid calling getParent() because it would return bogus results // avoid calling getParent() because it would return bogus results
// for the not-anymore transient node // for the not-anymore transient node
Node nparent = (node.parentHandle == null) ? null Node nparent = (node.parentHandle == null) ? null
@ -1081,6 +1092,7 @@ public final class Node implements INode, Serializable {
// This would be an alternative way to do it, without loading the subnodes: // This would be an alternative way to do it, without loading the subnodes:
// if (dbmap != null && dbmap.getSubnodeRelation () != null) // if (dbmap != null && dbmap.getSubnodeRelation () != null)
// retval = nmgr.getNode (this, subid, dbmap.getSubnodeRelation ()); // retval = nmgr.getNode (this, subid, dbmap.getSubnodeRelation ());
if ((retval != null) && (retval.parentHandle == null) && if ((retval != null) && (retval.parentHandle == null) &&
!"root".equalsIgnoreCase(retval.getPrototype())) { !"root".equalsIgnoreCase(retval.getPrototype())) {
retval.setParent(this); retval.setParent(this);
@ -2175,7 +2187,7 @@ public final class Node implements INode, Serializable {
// check if the main identity of this node is as a named property // check if the main identity of this node is as a named property
// or as an anonymous node in a collection // or as an anonymous node in a collection
if (n != this && !"root".equalsIgnoreCase(n.getPrototype())) { if (!n.isRelational() && n != this && !"root".equalsIgnoreCase(n.getPrototype())) {
// avoid calling getParent() because it would return bogus results // avoid calling getParent() because it would return bogus results
// for the not-anymore transient node // for the not-anymore transient node
Node nparent = (n.parentHandle == null) ? null Node nparent = (n.parentHandle == null) ? null
@ -2186,7 +2198,7 @@ public final class Node implements INode, Serializable {
if ((nparent == null) || if ((nparent == null) ||
((state != TRANSIENT) && (nparent.getState() == TRANSIENT))) { ((state != TRANSIENT) && (nparent.getState() == TRANSIENT))) {
n.setParent(this); n.setParent(this);
n.name = propname; n.setName(propname);
n.anonymous = false; n.anonymous = false;
} }
} }