diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java index 52699608..ee689e7a 100644 --- a/src/helma/objectmodel/db/Node.java +++ b/src/helma/objectmodel/db/Node.java @@ -48,6 +48,10 @@ public final class Node implements INode, Serializable { // the serialization version this object was read from (see readObject()) protected short version = 0; + /** + * Read this object instance from a stream. This does some smart conversion to + * update from previous serialization formats. + */ private void readObject (ObjectInputStream in) throws IOException { try { // as a general rule of thumb, if a string can be null use read/writeObject, @@ -105,6 +109,9 @@ public final class Node implements INode, Serializable { } } + /** + * Write out this instance to a stream + */ private void writeObject (ObjectOutputStream out) throws IOException { out.writeShort (5); // serialization version out.writeUTF (id); @@ -253,7 +260,7 @@ public final class Node implements INode, Serializable { Relation rel = (Relation) e.nextElement (); // NOTE: this should never be the case, since we're just looping through // mappnigs with a local db column - if (rel.direction != Relation.PRIMITIVE && rel.direction != Relation.FORWARD) + if (rel.reftype != Relation.PRIMITIVE && rel.reftype != Relation.REFERENCE) continue; Value val = rec.getValue (rel.getDbField ()); @@ -261,7 +268,7 @@ public final class Node implements INode, Serializable { if (val.isNull ()) continue; - Property newprop = new Property (rel.propname, this); + Property newprop = new Property (rel.propName, this); switch (val.type ()) { @@ -320,17 +327,14 @@ public final class Node implements INode, Serializable { if(propMap == null) propMap = new Hashtable (); - propMap.put (rel.propname.toLowerCase(), newprop); + propMap.put (rel.propName.toLowerCase(), newprop); // mark property as clean, since it's fresh from the db newprop.dirty = false; // if the property is a pointer to another node, change the property type to NODE - if (rel.direction == Relation.FORWARD) { + if (rel.reftype == Relation.REFERENCE && rel.usesPrimaryKey ()) { // FIXME: References to anything other than the primary key are not supported - if (rel.usesPrimaryKey ()) - newprop.nhandle = new NodeHandle (new DbKey (rel.other, newprop.getStringValue ())); - else - newprop.nhandle = new NodeHandle (new DbKey (rel.other, newprop.getStringValue (), rel.getRemoteField ())); + newprop.nhandle = new NodeHandle (new DbKey (rel.otherType, newprop.getStringValue ())); newprop.type = IProperty.NODE; } } @@ -445,13 +449,13 @@ public final class Node implements INode, Serializable { Node p = parentHandle.getNode (nmgr); DbMapping parentmap = p.getDbMapping (); Relation prel = parentmap.getPropertyRelation(); - if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) { - String propname = dbmap.columnNameToProperty (prel.getRemoteField ()); + if (prel != null && prel.subnodesAreProperties && prel.accessor != null) { + String propname = dbmap.columnNameToProperty (prel.accessor); String propvalue = getString (propname, false); if (propvalue != null && propvalue.length() > 0) { setName (propvalue); anonymous = false; - // nameProp = localrel.propname; + // nameProp = localrel.propName; } else { anonymous = true; } @@ -575,7 +579,8 @@ public final class Node implements INode, Serializable { public void setName (String name) { // "/" is used as delimiter, so it's not a legal char if (name.indexOf('/') > -1) - throw new RuntimeException ("The name of the node must not contain \"/\"."); + return; + // throw new RuntimeException ("The name of the node must not contain \"/\"."); if (name == null || name.trim().length() == 0) this.name = id; // use id as name else @@ -615,14 +620,11 @@ public final class Node implements INode, Serializable { if (parentmap != null) { // first try to retrieve name via generic property relation of parent Relation prel = parentmap.getPropertyRelation (); - if (prel != null && prel.other == dbmap && prel.direction == Relation.DIRECT) { + if (prel != null && prel.otherType == dbmap && prel.accessor != null) { // reverse look up property used to access this via parent - String dbfield = prel.getRemoteField (); - if (dbfield != null) { - Relation proprel = (Relation) dbmap.getDB2Prop ().get (dbfield); - if (proprel != null && proprel.propname != null) - newname = getString (proprel.propname, false); - } + Relation proprel = (Relation) dbmap.getDB2Prop ().get (prel.accessor); + if (proprel != null && proprel.propName != null) + newname = getString (proprel.propName, false); } } @@ -666,7 +668,7 @@ public final class Node implements INode, Serializable { if (dbm != null && dbm.getSubnodeGroupby () != null) { // check for groupby Relation rel = (Relation) dbmap.getDB2Prop ().get (dbm.getSubnodeGroupby()); - pn = pn.getSubnode (getString (rel.propname, false)); + pn = pn.getSubnode (getString (rel.propName, false)); } if (pn != null) { setParent ((Node) pn); @@ -716,8 +718,8 @@ public final class Node implements INode, Serializable { node.makePersistentCapable (); String n = node.getName(); - if (n.indexOf('/') > -1) - throw new RuntimeException ("\"/\" found in Node name."); + // if (n.indexOf('/') > -1) + // throw new RuntimeException ("\"/\" found in Node name."); // only lock node if it has to be modified for a change in subnodes if (!ignoreSubnodeChange ()) @@ -737,16 +739,18 @@ public final class Node implements INode, Serializable { if (dbmap != null) { Relation srel = dbmap.getSubnodeRelation (); if (srel != null && srel.groupby != null) try { - Relation groupbyRel = (Relation) srel.other.getDB2Prop ().get (srel.groupby); + Relation groupbyRel = (Relation) srel.otherType.getDB2Prop ().get (srel.groupby); String groupbyProp = (groupbyRel != null) ? - groupbyRel.propname : srel.groupby; + groupbyRel.propName : srel.groupby; String groupbyValue = node.getString (groupbyProp, false); INode groupbyNode = getNode (groupbyValue, false); // if group-by node doesn't exist, we'll create it if (groupbyNode == null) groupbyNode = getGroupbySubnode (groupbyValue, true); groupbyNode.addNode (node); - checkBackLink (node); + + srel.setConstraints (this, node); + return node; } catch (Exception x) { System.err.println ("Error adding groupby: "+x); @@ -773,10 +777,10 @@ public final class Node implements INode, Serializable { // check if properties are subnodes (_properties.aresubnodes=true) if (dbmap != null && node.dbmap != null) { Relation prel = dbmap.getPropertyRelation(); - if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) { - Relation localrel = node.dbmap.columnNameToRelation (prel.getRemoteField ()); + if (prel != null && prel.accessor != null) { + Relation localrel = node.dbmap.columnNameToRelation (prel.accessor); // if no relation from db column to prop name is found, assume that both are equal - String propname = localrel == null ? prel.getRemoteField() : localrel.propname; + String propname = localrel == null ? prel.accessor : localrel.propName; String prop = node.getString (propname, false); if (prop != null && prop.length() > 0) { INode old = getNode (prop, false); @@ -806,7 +810,8 @@ public final class Node implements INode, Serializable { } } - checkBackLink (node); + if (dbmap != null && dbmap.getSubnodeRelation () != null) + dbmap.getSubnodeRelation ().setConstraints (this, node); lastmodified = System.currentTimeMillis (); lastSubnodeChange = lastmodified; @@ -814,24 +819,6 @@ public final class Node implements INode, Serializable { return node; } - private void checkBackLink (Node node) { - // check if the subnode is in relational db and needs to link back to this - // in order to make it a subnode - if (dbmap != null) { - Relation srel = dbmap.getSubnodeRelation (); - if (srel != null && srel.direction == Relation.BACKWARD) { - Relation backlink = srel.other.columnNameToRelation (srel.getRemoteField()); - if (backlink != null && backlink.propname != null) { - if (node.get (backlink.propname, false) == null) { - if (this.state == VIRTUAL) - node.setString (backlink.propname, getNonVirtualHomeID()); - else - node.setString (backlink.propname, getID()); - } - } - } - } - } public INode createNode () { return createNode (null, numberOfNodes ()); // create new node at end of subnode array @@ -899,11 +886,11 @@ public final class Node implements INode, Serializable { if ("".equals (subid)) { return this; } else if (subid != null) { + loadNodes (); if (subnodes == null || subnodes.size() == 0) return null; - // check if there is a group-by relation NodeHandle nhandle = null; int l = subnodes.size (); for (int i=0; i