From ae0536eb261e0677ae657f3cf64cd87b7e938e24 Mon Sep 17 00:00:00 2001 From: hns Date: Thu, 11 Oct 2007 12:21:40 +0000 Subject: [PATCH] * Allow _parent to consist of three elements, such as page.comments.blocked. Fixes bug 563 - http://helma.org/bugs/show_bug.cgi?id=563 * Throw an exception when adding to a collection with accessname defined and the collection already contains an object with the given name. Previously, the old object was deleted from the database. Fixes bug 561 - http://helma.org/bugs/show_bug.cgi?id=561 --- src/helma/objectmodel/db/Node.java | 28 ++++++++++++---------- src/helma/objectmodel/db/ParentInfo.java | 30 +++++++++++++----------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java index 0e151feb..619baa07 100644 --- a/src/helma/objectmodel/db/Node.java +++ b/src/helma/objectmodel/db/Node.java @@ -789,13 +789,18 @@ public final class Node implements INode, Serializable { if (pn2 == null) { getApp().logError("Error: Can't retrieve parent node " + pinfo + " for " + this); + } else if (pinfo.collectionname != null) { + pn2 = (Node) pn2.getNode(pinfo.collectionname); } else if (pn2.equals(this)) { + // a special case we want to support: virtualname is actually + // a reference to this node, not a collection containint this node. setParent(pn); name = pinfo.virtualname; anonymous = false; return pn; } - pn = pn2; + + pn = pn2; } DbMapping dbm = (pn == null) ? null : pn.getDbMapping(); @@ -952,11 +957,11 @@ public final class Node implements INode, Serializable { } // check if subnode accessname is set. If so, check if another node - // uses the same access name and remove it - if ((dbmap != null) && (node.dbmap != null)) { + // uses the same access name, throwing an exception if so. + if (dbmap != null && node.dbmap != null) { Relation prel = dbmap.getSubnodeRelation(); - if ((prel != null) && (prel.accessName != null)) { + if (prel != null && prel.accessName != null) { Relation localrel = node.dbmap.columnNameToRelation(prel.accessName); // if no relation from db column to prop name is found, @@ -965,15 +970,14 @@ public final class Node implements INode, Serializable { : localrel.propName; String prop = node.getString(propname); - if ((prop != null) && (prop.length() > 0)) { + if (prop != null && prop.length() > 0) { INode old = (INode) getChildElement(prop); - if ((old != null) && (old != node)) { - // FIXME: we delete the existing node here, - // but actually the app developer should prevent this from - // happening, so it might be better to throw an exception. - old.remove(); - this.removeNode(old); + if (old != null && old != node) { + // A node with this name already exists. This is a + // programming error, throw an exception. + throw new RuntimeException("An object named \"" + prop + + "\" is already contained in the collection."); } if (state != TRANSIENT) { @@ -2714,7 +2718,7 @@ public final class Node implements INode, Serializable { * @return the number of loaded nodes within this collection update */ public int updateSubnodes () { - // FIXME: what do we do if dbmap is null + // TODO: what do we do if dbmap is null if (dbmap == null) { throw new RuntimeException (this + " doesn't have a DbMapping"); } diff --git a/src/helma/objectmodel/db/ParentInfo.java b/src/helma/objectmodel/db/ParentInfo.java index 6fbd2199..bbd8b489 100644 --- a/src/helma/objectmodel/db/ParentInfo.java +++ b/src/helma/objectmodel/db/ParentInfo.java @@ -16,6 +16,8 @@ package helma.objectmodel.db; +import helma.util.StringUtils; + /** * This class describes a parent relation between releational nodes. @@ -23,38 +25,38 @@ package helma.objectmodel.db; public class ParentInfo { public final String propname; public final String virtualname; + public final String collectionname; public final boolean isroot; /** * Creates a new ParentInfo object. * - * @param desc ... + * @param desc a single parent info descriptor */ public ParentInfo(String desc) { // [named] isn't used anymore, we just want to keep the parsing compatible. int n = desc.indexOf("[named]"); - String d = n>-1 ? desc.substring(0, n) : desc; + desc = n > -1 ? desc.substring(0, n) : desc; - int dot = d.indexOf("."); + String[] parts = StringUtils.split(desc, "."); - if (dot > -1) { - propname = d.substring(0, dot).trim(); - virtualname = d.substring(dot + 1).trim(); - } else { - propname = d.trim(); - virtualname = null; - } + propname = parts.length > 0 ? parts[0].trim() : null; + virtualname = parts.length > 1 ? parts[1].trim() : null; + collectionname = parts.length > 2 ? parts[2].trim() : null; isroot = "root".equalsIgnoreCase(propname); } /** - * - * - * @return ... + * @return a string representation of the parent info */ public String toString() { - return "ParentInfo[" + propname + "," + virtualname + "]"; + StringBuffer b = new StringBuffer("ParentInfo[").append(propname); + if (virtualname != null) + b.append(".").append(virtualname); + if (collectionname != null) + b.append(".").append(collectionname); + return b.append("]").toString(); } }