switched everything from the old id/mapping to the new
NodeHandle references. This breaks serialization compatibility with prior versions.
This commit is contained in:
parent
7bdcdcd65f
commit
a90c945bae
1 changed files with 238 additions and 248 deletions
|
@ -25,8 +25,8 @@ import com.workingdogs.village.*;
|
|||
|
||||
public class Node implements INode, Serializable {
|
||||
|
||||
// The ID of this node's parent node
|
||||
protected String parentID;
|
||||
// The handle to the node's parent
|
||||
protected NodeHandle parentHandle;
|
||||
// Ordered list of subnodes of this node
|
||||
private List subnodes;
|
||||
// Named subnodes (properties) of this node
|
||||
|
@ -52,7 +52,11 @@ public class Node implements INode, Serializable {
|
|||
int version = in.readShort ();
|
||||
id = in.readUTF ();
|
||||
name = in.readUTF ();
|
||||
parentID = (String) in.readObject ();
|
||||
if (version < 5)
|
||||
throw new IOException ("Unsupported Data Format (pre 1.2)");
|
||||
// parentHandle = new NodeHandle (new Key (null, (String) in.readObject ()));
|
||||
else
|
||||
parentHandle = (NodeHandle) in.readObject ();
|
||||
created = in.readLong ();
|
||||
lastmodified = in.readLong ();
|
||||
if (version < 4) {
|
||||
|
@ -75,10 +79,10 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
private void writeObject (ObjectOutputStream out) throws IOException {
|
||||
out.writeShort (4); // serialization version
|
||||
out.writeShort (5); // serialization version
|
||||
out.writeUTF (id);
|
||||
out.writeUTF (name);
|
||||
out.writeObject (parentID);
|
||||
out.writeObject (parentHandle);
|
||||
out.writeLong (created);
|
||||
out.writeLong (lastmodified);
|
||||
DbMapping smap = dbmap == null ? null : dbmap.getSubnodeMapping ();
|
||||
|
@ -93,12 +97,18 @@ public class Node implements INode, Serializable {
|
|||
out.writeObject (prototype);
|
||||
}
|
||||
|
||||
transient String prototype;
|
||||
transient INode cacheNode;
|
||||
private transient String prototype;
|
||||
|
||||
private transient NodeHandle handle;
|
||||
|
||||
private transient INode cacheNode;
|
||||
|
||||
transient WrappedNodeManager nmgr;
|
||||
|
||||
transient DbMapping dbmap;
|
||||
|
||||
transient Key primaryKey = null;
|
||||
transient DbMapping parentmap;
|
||||
|
||||
transient String subnodeRelation = null;
|
||||
transient long lastSubnodeFetch = 0;
|
||||
transient long lastSubnodeChange = 0;
|
||||
|
@ -117,12 +127,27 @@ public class Node implements INode, Serializable {
|
|||
static final long serialVersionUID = -3740339688506633675L;
|
||||
|
||||
/**
|
||||
* This constructor is only used for instances of the NullNode subclass. Do not use for ordinary Nodes!
|
||||
* This constructor is only used for instances of the NullNode subclass. Do not use for ordinary Nodes!<
|
||||
*/
|
||||
public Node () {
|
||||
Node () {
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Node with the given name. Only used by NodeManager for "root nodes" and
|
||||
* not in a Transaction context, which is why we can immediately mark it as CLEAN.
|
||||
*/
|
||||
protected Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.id = id;
|
||||
this.name = name == null || "".equals (name) ? id : name;
|
||||
if (prototype != null)
|
||||
setPrototype (prototype);
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
markAs (CLEAN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used for virtual nodes.
|
||||
*/
|
||||
|
@ -131,18 +156,38 @@ public class Node implements INode, Serializable {
|
|||
setParent (home);
|
||||
// this.dbmap = null;
|
||||
// generate a key for the virtual node that can't be mistaken for a JDBC-URL
|
||||
this.id = Key.makeVirtualID (parentmap, parentID, propname);
|
||||
primaryKey = new SyntheticKey (home.getKey (), propname);
|
||||
this.id = primaryKey.getID ();
|
||||
this.name = propname;
|
||||
this.anonymous = false;
|
||||
setPrototype (prototype);
|
||||
this.state = VIRTUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Node with the given name. This is used for ordinary transient nodes.
|
||||
*/
|
||||
public Node (String n, String prototype, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.prototype = prototype;
|
||||
dbmap = nmgr.getDbMapping (prototype);
|
||||
// the id is only generated when the node is actually checked into db.
|
||||
// id = nmgr.generateID (dbmap);
|
||||
// checkWriteLock ();
|
||||
this.name = n == null ? "" : n;
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
adoptName = true;
|
||||
state = TRANSIENT;
|
||||
// markAs (TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used for nodes being stored in a relational database table.
|
||||
*/
|
||||
public Node (DbMapping dbmap, Record rec, WrappedNodeManager nmgr) throws DataSetException {
|
||||
|
||||
this.nmgr = nmgr;
|
||||
// see what prototype/DbMapping this object should use
|
||||
DbMapping m = dbmap;
|
||||
String protoField= dbmap.getPrototypeField ();
|
||||
|
@ -161,7 +206,6 @@ public class Node implements INode, Serializable {
|
|||
setPrototype (m.getTypeName ());
|
||||
this.dbmap = m;
|
||||
|
||||
this.nmgr = nmgr;
|
||||
id = rec.getValue (dbmap.getIDField ()).asString ();
|
||||
checkWriteLock ();
|
||||
String nameField = dbmap.getNameField ();
|
||||
|
@ -170,8 +214,7 @@ public class Node implements INode, Serializable {
|
|||
name = m.getTypeName() + " " + id;
|
||||
// set parent for user objects to internal userroot node
|
||||
if ("user".equals (prototype)) {
|
||||
this.parentID = "1";
|
||||
this.parentmap = nmgr.getDbMapping("__userroot__");
|
||||
parentHandle = new NodeHandle (new DbKey (null, "1"));
|
||||
anonymous = false;
|
||||
}
|
||||
|
||||
|
@ -255,7 +298,7 @@ public class Node implements INode, Serializable {
|
|||
|
||||
// if the property is a pointer to another node, change the property type to NODE
|
||||
if (rel.direction == Relation.FORWARD) {
|
||||
newprop.nvalueID = newprop.getStringValue ();
|
||||
newprop.nhandle = new NodeHandle (new DbKey (rel.other, newprop.getStringValue ()));
|
||||
newprop.type = IProperty.NODE;
|
||||
}
|
||||
}
|
||||
|
@ -263,93 +306,6 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Node with the given name.
|
||||
*/
|
||||
public Node (String n, String prototype, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.prototype = prototype;
|
||||
dbmap = nmgr.getDbMapping (prototype);
|
||||
id = nmgr.generateID (dbmap);
|
||||
// checkWriteLock ();
|
||||
this.name = n == null || "".equals (n) ? id : n;
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
adoptName = true;
|
||||
markAs (TRANSIENT);
|
||||
// nmgr.registerNode (this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Node with the given name. Only used by NodeManager for "root nodes" and
|
||||
* not in a Transaction context, which is why we can immediately mark it as CLEAN.
|
||||
*/
|
||||
protected Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.id = id;
|
||||
this.name = name == null || "".equals (name) ? id : name;
|
||||
if (prototype != null)
|
||||
setPrototype (prototype);
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
markAs (CLEAN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of Node, transforming from another implementation of
|
||||
* interface INode. This Constructor is used when a transient
|
||||
* node is converted into a persistent-capable one, hence the status is set to NEW.
|
||||
*/
|
||||
/* private Node (INode node, Hashtable ntable, boolean conversionRoot, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.dbmap = node.getDbMapping ();
|
||||
this.id = nmgr.generateID (dbmap);
|
||||
checkWriteLock ();
|
||||
this.name = node.getName ();
|
||||
this.prototype = node.getPrototype ();
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
ntable.put (node, this);
|
||||
// only take over name from property if this is not the root of the current node conversion
|
||||
adoptName = !conversionRoot;
|
||||
for (Enumeration e = node.getSubnodes (); e.hasMoreElements (); ) {
|
||||
INode next = (INode) e.nextElement ();
|
||||
Node nextc = (next instanceof Node) ? (Node) next : (Node) ntable.get (next); // is this a Node already?
|
||||
if (nextc == null)
|
||||
nextc = new Node (next, ntable, true, nmgr);
|
||||
if (nextc.state == INVALID)
|
||||
nextc = nmgr.getNode (nextc.getID (), nextc.getDbMapping ());
|
||||
addNode (nextc);
|
||||
}
|
||||
for (Enumeration e = node.properties (); e.hasMoreElements (); ) {
|
||||
IProperty next = node.get ((String) e.nextElement (), false);
|
||||
if (next == null)
|
||||
continue;
|
||||
int t = next.getType ();
|
||||
if (t == IProperty.NODE) {
|
||||
INode n = next.getNodeValue ();
|
||||
Node nextc = (n instanceof Node) ? (Node) n : (Node) ntable.get (n); // is this a Node already?
|
||||
if (nextc == null)
|
||||
nextc = new Node (n, ntable, true, nmgr);
|
||||
if (nextc.state == INVALID)
|
||||
nextc = nmgr.getNode (nextc.getID (), nextc.getDbMapping ());
|
||||
setNode (next.getName (), nextc);
|
||||
} else if (t == IProperty.STRING) {
|
||||
setString (next.getName (), next.getStringValue ());
|
||||
} else if (t == IProperty.INTEGER) {
|
||||
setInteger (next.getName (), next.getIntegerValue ());
|
||||
} else if (t == IProperty.FLOAT) {
|
||||
setFloat (next.getName (), next.getFloatValue ());
|
||||
} else if (t == IProperty.BOOLEAN) {
|
||||
setBoolean (next.getName (), next.getBooleanValue ());
|
||||
} else if (t == IProperty.DATE) {
|
||||
setDate (next.getName (), next.getDateValue ());
|
||||
} else if (t == IProperty.JAVAOBJECT) {
|
||||
setJavaObject (next.getName (), next.getJavaObjectValue ());
|
||||
}
|
||||
}
|
||||
adoptName = true; // switch back to normal name adoption behaviour
|
||||
markAs (NEW);
|
||||
// nmgr.registerNode (this);
|
||||
} */
|
||||
|
||||
protected synchronized void checkWriteLock () {
|
||||
// System.err.println ("registering writelock for "+this.getName ()+" ("+lock+") to "+Thread.currentThread ());
|
||||
|
@ -422,6 +378,8 @@ public class Node implements INode, Serializable {
|
|||
*/
|
||||
|
||||
public String getID () {
|
||||
if (state == TRANSIENT)
|
||||
throw new RuntimeException ("getID called on transient Node: "+this);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -445,20 +403,23 @@ public class Node implements INode, Serializable {
|
|||
public String getNameOrID () {
|
||||
// if subnodes are also mounted as properties, try to get the "nice" prop value
|
||||
// instead of the id by turning the anonymous flag off.
|
||||
// HACK: work around this for user objects to alsways return a URL like /users/username
|
||||
if ("user".equalsIgnoreCase (prototype)) {
|
||||
// Work around this for user objects to alsways return a URL like /users/username
|
||||
if ("user".equalsIgnoreCase (prototype)) {
|
||||
anonymous = false;
|
||||
} else if (parentmap != null) {
|
||||
Relation prel = parentmap.getPropertyRelation();
|
||||
if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) try {
|
||||
Relation localrel = dbmap.columnNameToProperty (prel.getRemoteField ());
|
||||
String propvalue = getString (localrel.propname, false);
|
||||
if (propvalue != null && propvalue.length() > 0) {
|
||||
setName (propvalue);
|
||||
anonymous = false;
|
||||
// nameProp = localrel.propname;
|
||||
} else {
|
||||
anonymous = true;
|
||||
} else if (parentHandle != null) {
|
||||
try {
|
||||
DbMapping parentmap = parentHandle.getDbMapping (nmgr);
|
||||
Relation prel = parentmap.getPropertyRelation();
|
||||
if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) {
|
||||
Relation localrel = dbmap.columnNameToProperty (prel.getRemoteField ());
|
||||
String propvalue = getString (localrel.propname, false);
|
||||
if (propvalue != null && propvalue.length() > 0) {
|
||||
setName (propvalue);
|
||||
anonymous = false;
|
||||
// nameProp = localrel.propname;
|
||||
} else {
|
||||
anonymous = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// just fall back to default method
|
||||
|
@ -533,10 +494,7 @@ public class Node implements INode, Serializable {
|
|||
public void setDbMapping (DbMapping dbmap) {
|
||||
if (this.dbmap != dbmap) {
|
||||
this.dbmap = dbmap;
|
||||
primaryKey = null;
|
||||
try {
|
||||
((Transactor) Thread.currentThread()).visitCleanNode (this);
|
||||
} catch (ClassCastException ignore) {}
|
||||
// primaryKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -545,13 +503,21 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
public Key getKey () {
|
||||
if (state == TRANSIENT)
|
||||
throw new RuntimeException ("getKey called on transient Node: "+this);
|
||||
if (dbmap == null && prototype != null && nmgr != null)
|
||||
dbmap = nmgr.getDbMapping (prototype);
|
||||
if (primaryKey == null)
|
||||
primaryKey = new Key (dbmap, id);
|
||||
primaryKey = new DbKey (dbmap, id);
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
public NodeHandle getHandle () {
|
||||
if (handle == null)
|
||||
handle = new NodeHandle (this);
|
||||
return handle;
|
||||
}
|
||||
|
||||
public void setSubnodeRelation (String rel) {
|
||||
if ((rel == null && this.subnodeRelation == null)
|
||||
|| (rel != null && rel.equalsIgnoreCase (this.subnodeRelation)))
|
||||
|
@ -584,8 +550,7 @@ public class Node implements INode, Serializable {
|
|||
* the ID + DB map combo.
|
||||
*/
|
||||
public void setParent (Node parent) {
|
||||
this.parentID = parent == null ? null : parent.getID();
|
||||
this.parentmap = parent == null ? null : parent.getDbMapping();
|
||||
parentHandle = parent == null ? null : parent.getHandle ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -595,21 +560,21 @@ public class Node implements INode, Serializable {
|
|||
*/
|
||||
public void setParent (Node parent, String propertyName) {
|
||||
// we only do that for relational nodes.
|
||||
if (dbmap == null || !dbmap.isRelational ())
|
||||
if (!isRelational ())
|
||||
return;
|
||||
|
||||
String oldParentID = parentID;
|
||||
parentID = parent == null ? null : parent.getID();
|
||||
parentmap = parent == null ? null : parent.getDbMapping();
|
||||
NodeHandle oldParentHandle = parentHandle;
|
||||
parentHandle = parent == null ? null : parent.getHandle ();
|
||||
|
||||
if (parentID == null || parentID.equals (oldParentID))
|
||||
if (parentHandle == null || parentHandle.equals (oldParentHandle))
|
||||
// nothing changed, no need to find access property
|
||||
return;
|
||||
|
||||
if (propertyName == null) {
|
||||
if (parent != null && propertyName == null) {
|
||||
// see if we can find out the propertyName by ourselfes by looking at the
|
||||
// parent's property relation
|
||||
String newname = null;
|
||||
DbMapping parentmap = parent.getDbMapping ();
|
||||
if (parentmap != null) {
|
||||
// first try to retrieve name via generic property relation of parent
|
||||
Relation prel = parentmap.getPropertyRelation ();
|
||||
|
@ -645,8 +610,7 @@ public class Node implements INode, Serializable {
|
|||
|
||||
// check what's specified in the type.properties for this node.
|
||||
ParentInfo[] parentInfo = null;
|
||||
if (dbmap != null && dbmap.isRelational () &&
|
||||
(lastParentSet < dbmap.getLastTypeChange() || lastParentSet < lastmodified))
|
||||
if (isRelational () && (lastParentSet < dbmap.getLastTypeChange() || lastParentSet < lastmodified))
|
||||
parentInfo = dbmap.getParentInfo ();
|
||||
|
||||
// check if current parent candidate matches presciption, if not, try to get it
|
||||
|
@ -679,10 +643,9 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
// fall back to heuristic parent (the node that fetched this one from db)
|
||||
if (parentID == null) {
|
||||
if (parentHandle == null)
|
||||
return null;
|
||||
}
|
||||
return nmgr.getNode (parentID, parentmap);
|
||||
return parentHandle.getNode (nmgr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -690,9 +653,9 @@ public class Node implements INode, Serializable {
|
|||
* Get parent, using cached info if it exists.
|
||||
*/
|
||||
public Node getCachedParent () {
|
||||
if (parentID == null)
|
||||
if (parentHandle == null)
|
||||
return null;
|
||||
return nmgr.getNode (parentID, parentmap);
|
||||
return parentHandle.getNode (nmgr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -758,22 +721,17 @@ public class Node implements INode, Serializable {
|
|||
|
||||
if (where < 0 || where > numberOfNodes ())
|
||||
where = numberOfNodes ();
|
||||
if (node.parentID != null) {
|
||||
// this makes the job of addLink, which means that addLink and addNode
|
||||
// are functionally equivalent now.
|
||||
if (!node.parentID.equals (id) || !node.anonymous) {
|
||||
node.registerLink (this);
|
||||
}
|
||||
}
|
||||
|
||||
if (subnodes != null && subnodes.contains (node.getID ())) {
|
||||
NodeHandle nhandle = node.getHandle ();
|
||||
if (subnodes != null && subnodes.contains (nhandle)) {
|
||||
// Node is already subnode of this - just move to new position
|
||||
subnodes.remove (node.getID ());
|
||||
subnodes.remove (nhandle);
|
||||
where = Math.min (where, numberOfNodes ());
|
||||
subnodes.add (where, node.getID ());
|
||||
subnodes.add (where, nhandle);
|
||||
} else {
|
||||
if (subnodes == null) subnodes = new ExternalizableVector ();
|
||||
subnodes.add (where, node.getID ());
|
||||
if (subnodes == null)
|
||||
subnodes = new ExternalizableVector ();
|
||||
subnodes.add (where, nhandle);
|
||||
|
||||
// check if properties are subnodes (_properties.aresubnodes=true)
|
||||
if (dbmap != null && node.dbmap != null) {
|
||||
|
@ -795,9 +753,19 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
if (node.parentID == null && !"root".equalsIgnoreCase (node.getPrototype ())) {
|
||||
node.setParent (this);
|
||||
node.anonymous = true;
|
||||
if (!"root".equalsIgnoreCase (node.getPrototype ())) {
|
||||
Node nparent = (Node) node.getParent ();
|
||||
// if the node doesn't have a parent yet, or it has one but it's transient while we are
|
||||
// persistent, make this the nodes new parent.
|
||||
if (nparent == null || (state != TRANSIENT && nparent.getState () == TRANSIENT)) {
|
||||
node.setParent (this);
|
||||
node.anonymous = true;
|
||||
} else if (nparent != null && (nparent != this || !node.anonymous)) {
|
||||
// this makes the additional job of addLink, registering that we have a link to a node in our
|
||||
// subnodes that actually sits somewhere else. This means that addLink and addNode
|
||||
// are actually the same now.
|
||||
node.registerLinkFrom (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -856,14 +824,18 @@ public class Node implements INode, Serializable {
|
|||
|
||||
|
||||
/**
|
||||
* register a node that links to this node.
|
||||
* register a node that links to this node so we can notify it when we cease to exist.
|
||||
* this is only necessary if we are a non-relational node, since for relational nodes
|
||||
* the referring object will notice that we've gone at runtime.
|
||||
*/
|
||||
protected void registerLink (Node from) {
|
||||
protected void registerLinkFrom (Node from) {
|
||||
if (isRelational ())
|
||||
return;
|
||||
if (links == null)
|
||||
links = new ExternalizableVector ();
|
||||
Object fromID = from.getID ();
|
||||
if (!links.contains (fromID))
|
||||
links.add (fromID);
|
||||
Object fromHandle = from.getHandle ();
|
||||
if (!links.contains (fromHandle))
|
||||
links.add (fromHandle);
|
||||
}
|
||||
|
||||
public INode getSubnode (String path) {
|
||||
|
@ -878,25 +850,28 @@ public class Node implements INode, Serializable {
|
|||
retval = this;
|
||||
} else {
|
||||
runner.loadNodes ();
|
||||
boolean found = runner.subnodes == null ? false : runner.subnodes.contains (next);
|
||||
Relation srel = null;
|
||||
DbMapping smap = null;
|
||||
if (runner.dbmap != null) {
|
||||
srel = runner.dbmap.getSubnodeRelation ();
|
||||
smap = runner.dbmap.getSubnodeMapping ();
|
||||
}
|
||||
|
||||
// check if there is a group-by relation
|
||||
NodeHandle nhandle = null;
|
||||
if (srel != null && srel.groupby != null)
|
||||
nhandle = new NodeHandle (new SyntheticKey (runner.getKey (), next));
|
||||
else
|
||||
nhandle = new NodeHandle (new DbKey (smap, next));
|
||||
boolean found = runner.subnodes == null ? false : runner.subnodes.contains (nhandle);
|
||||
|
||||
if (!found)
|
||||
if (!found) {
|
||||
retval = null;
|
||||
else {
|
||||
Relation srel = null;
|
||||
DbMapping smap = null;
|
||||
if (runner.dbmap != null) {
|
||||
srel = runner.dbmap.getSubnodeRelation ();
|
||||
smap = runner.dbmap.getSubnodeMapping ();
|
||||
}
|
||||
// check if there is a group-by relation
|
||||
if (srel != null && srel.groupby != null)
|
||||
retval = nmgr.getNode (this, next, srel);
|
||||
else
|
||||
retval = nmgr.getNode (next, smap);
|
||||
} else {
|
||||
retval = nhandle.getNode (nmgr);
|
||||
}
|
||||
|
||||
if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
|
||||
if (retval != null && retval.parentHandle == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
|
||||
retval.setParent (runner);
|
||||
retval.anonymous = true;
|
||||
}
|
||||
|
@ -914,20 +889,16 @@ public class Node implements INode, Serializable {
|
|||
if (subnodes == null)
|
||||
return null;
|
||||
|
||||
Relation srel = null;
|
||||
DbMapping smap = null;
|
||||
if (dbmap != null) {
|
||||
srel = dbmap.getSubnodeRelation ();
|
||||
if (dbmap != null)
|
||||
smap = dbmap.getSubnodeMapping ();
|
||||
}
|
||||
|
||||
Node retval = null;
|
||||
if (subnodes.size () > index) {
|
||||
// check if there is a group-by relation
|
||||
if (srel != null && srel.groupby != null)
|
||||
retval = nmgr.getNode (this, (String) subnodes.get (index), srel);
|
||||
else
|
||||
retval = nmgr.getNode ((String) subnodes.get (index), smap);
|
||||
if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
|
||||
retval = ((NodeHandle) subnodes.get (index)).getNode (nmgr);
|
||||
|
||||
if (retval != null && retval.parentHandle == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
|
||||
retval.setParent (this);
|
||||
retval.anonymous = true;
|
||||
}
|
||||
|
@ -940,7 +911,8 @@ public class Node implements INode, Serializable {
|
|||
if (subnodes == null)
|
||||
subnodes = new ExternalizableVector ();
|
||||
|
||||
if (subnodes.contains (sid) || create) try {
|
||||
NodeHandle ghandle = new NodeHandle (new SyntheticKey (getKey(), sid));
|
||||
if (subnodes.contains (ghandle) || create) try {
|
||||
Relation srel = dbmap.getSubnodeRelation ();
|
||||
Relation prel = dbmap.getPropertyRelation ();
|
||||
boolean relational = srel.other != null && srel.other.isRelational ();
|
||||
|
@ -976,7 +948,7 @@ public class Node implements INode, Serializable {
|
|||
node.setPrototype (gsrel.prototype);
|
||||
} else {
|
||||
setNode (sid, node);
|
||||
subnodes.add (node.getID ());
|
||||
subnodes.add (node.getHandle ());
|
||||
}
|
||||
nmgr.evictKey (node.getKey ());
|
||||
return node;
|
||||
|
@ -1014,7 +986,7 @@ public class Node implements INode, Serializable {
|
|||
} else {
|
||||
// removed just a link, not the main node.
|
||||
if (n.links != null) {
|
||||
n.links.remove (this.id);
|
||||
n.links.remove (getHandle ());
|
||||
if (n.state == CLEAN) n.markAs (MODIFIED);
|
||||
}
|
||||
}
|
||||
|
@ -1026,7 +998,7 @@ public class Node implements INode, Serializable {
|
|||
*/
|
||||
protected void releaseNode (Node node) {
|
||||
if (subnodes != null)
|
||||
subnodes.remove (node.getID ());
|
||||
subnodes.remove (node.getHandle ());
|
||||
|
||||
lastSubnodeChange = System.currentTimeMillis ();
|
||||
|
||||
|
@ -1041,7 +1013,7 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
// check if subnodes are handled as virtual fs
|
||||
// check if subnodes are also accessed as properties. If so, also unset the property
|
||||
if (dbmap != null && node.dbmap != null) {
|
||||
Relation prel = dbmap.getPropertyRelation();
|
||||
if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) {
|
||||
|
@ -1072,22 +1044,22 @@ public class Node implements INode, Serializable {
|
|||
*/
|
||||
protected void deepRemoveNode () {
|
||||
|
||||
// notify nodes that link to this node that it is being deleted.
|
||||
// notify nodes that link to this node being deleted.
|
||||
int l = links == null ? 0 : links.size ();
|
||||
for (int i = 0; i < l; i++) {
|
||||
// TODO: solve dbmap problem
|
||||
Node link = nmgr.getNode ((String) links.get (i), null);
|
||||
if (link != null) link.releaseNode (this);
|
||||
NodeHandle lhandle = (NodeHandle) links.get (i);
|
||||
Node link = lhandle.getNode (nmgr);
|
||||
if (link != null)
|
||||
link.releaseNode (this);
|
||||
}
|
||||
|
||||
// clean up all nodes that use n as a property
|
||||
// clean up all nodes that refer to this as a property
|
||||
if (proplinks != null) {
|
||||
for (Iterator e1 = proplinks.iterator (); e1.hasNext (); ) try {
|
||||
String pid = (String) e1.next ();
|
||||
Node pnode = nmgr.getNode (pid, null);
|
||||
if (pnode != null) {
|
||||
nmgr.logEvent("Warning: Not unsetting node property of "+pnode.getFullName ());
|
||||
}
|
||||
NodeHandle phandle = (NodeHandle) e1.next ();
|
||||
Node pnode = phandle.getNode (nmgr);
|
||||
if (pnode != null)
|
||||
nmgr.logEvent("Warning: Not unsetting node property of "+pnode.getName ());
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
|
@ -1113,7 +1085,7 @@ public class Node implements INode, Serializable {
|
|||
// getParent() is heuristical/implicit for relational nodes, so we don't base
|
||||
// a cascading delete on that criterium for relational nodes.
|
||||
Node n = (Node) v.get (i);
|
||||
if (n.dbmap == null || !n.dbmap.isRelational())
|
||||
if (!n.isRelational())
|
||||
removeNode (n);
|
||||
}
|
||||
}
|
||||
|
@ -1130,14 +1102,18 @@ public class Node implements INode, Serializable {
|
|||
if (subnodes == null)
|
||||
return -1;
|
||||
// if the node contains relational groupby subnodes, the subnodes vector contains the names instead of ids.
|
||||
Relation srel = dbmap == null ? null : dbmap.getSubnodeRelation ();
|
||||
/* Relation srel = dbmap == null ? null : dbmap.getSubnodeRelation ();
|
||||
if (srel != null && srel.groupby != null && srel.other != null && srel.other.isRelational ()) {
|
||||
if (n.getParent () != this)
|
||||
return -1;
|
||||
else
|
||||
return subnodes.indexOf (n.getName ());
|
||||
return subnodes.indexOf (new SyntheticKey (getKey (), n.getID ());
|
||||
} else
|
||||
return subnodes.indexOf (n.getID ());
|
||||
return subnodes.indexOf (n.getKey ());*/
|
||||
if (!(n instanceof Node))
|
||||
return -1;
|
||||
Node node = (Node) n;
|
||||
return subnodes.indexOf (node.getHandle ());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1251,7 +1227,7 @@ public class Node implements INode, Serializable {
|
|||
}
|
||||
|
||||
public String getParentInfo () {
|
||||
return "anonymous:"+anonymous+",parentID:"+parentID+",parentmap:"+parentmap+",parent:"+getParent();
|
||||
return "anonymous:"+anonymous+",parentHandle"+parentHandle+",parent:"+getParent();
|
||||
}
|
||||
|
||||
protected Property getProperty (String propname, boolean inherit) {
|
||||
|
@ -1265,31 +1241,41 @@ public class Node implements INode, Serializable {
|
|||
DbMapping pmap = dbmap == null ? null : dbmap.getExactPropertyMapping (propname);
|
||||
if (pmap != null && prop != null && prop.type != IProperty.NODE) {
|
||||
// this is a relational node stored by id but we still think it's just a string. fix it
|
||||
prop.nvalueID = prop.getStringValue ();
|
||||
prop.nhandle = new NodeHandle (new DbKey (pmap, prop.getStringValue ()));
|
||||
prop.type = IProperty.NODE;
|
||||
}
|
||||
|
||||
|
||||
// the property does not exist in our propmap - see if we can create it on the fly,
|
||||
// either because it is mapped from a relational database or defined as virtual node
|
||||
if (prop == null && dbmap != null) {
|
||||
Relation prel = dbmap.getPropertyRelation (propname);
|
||||
if (prel == null)
|
||||
prel = dbmap.getPropertyRelation ();
|
||||
if (prel != null && (prel.direction == Relation.DIRECT || prel.virtual)) {
|
||||
// this *may* be a relational node stored by property name
|
||||
try {
|
||||
Node pn = nmgr.getNode (this, propname, prel);
|
||||
if (pn != null) {
|
||||
if (pn.parentID == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
|
||||
pn.setParent (this);
|
||||
pn.name = propname;
|
||||
pn.anonymous = false;
|
||||
}
|
||||
prop = new Property (propname, this, pn);
|
||||
}
|
||||
} catch (RuntimeException nonode) {
|
||||
// wasn't a node after all
|
||||
/* if (prel != null && prel.virtual && prel.other != null && !prel.other.isRelational ()) {
|
||||
Node pn = (Node) createNode (propname);
|
||||
if (prel.prototype != null) {
|
||||
pn.setPrototype (prel.prototype);
|
||||
}
|
||||
}
|
||||
prop = (Property) propMap.get (propname);
|
||||
|
||||
} else { */
|
||||
if (prel == null)
|
||||
prel = dbmap.getPropertyRelation ();
|
||||
if (prel != null && (prel.direction == Relation.DIRECT || prel.virtual)) {
|
||||
// this may be a relational node stored by property name
|
||||
try {
|
||||
Node pn = nmgr.getNode (this, propname, prel);
|
||||
if (pn != null) {
|
||||
if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
|
||||
pn.setParent (this);
|
||||
pn.name = propname;
|
||||
pn.anonymous = false;
|
||||
}
|
||||
prop = new Property (propname, this, pn);
|
||||
}
|
||||
} catch (RuntimeException nonode) {
|
||||
// wasn't a node after all
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
if (prop == null && inherit && getParent () != null) {
|
||||
prop = ((Node) getParent ()).getProperty (propname, inherit);
|
||||
|
@ -1393,12 +1379,12 @@ public class Node implements INode, Serializable {
|
|||
|
||||
// check if this may have an effect on the node's URL when using subnodesAreProperties
|
||||
// but only do this if we already have a parent set, i.e. if we are already stored in the db
|
||||
INode parent = parentID == null ? null : getParent ();
|
||||
INode parent = parentHandle == null ? null : getParent ();
|
||||
|
||||
if (parent != null && parent.getDbMapping() != null) {
|
||||
// check if this node is already registered with the old name; if so, remove it.
|
||||
// then set parent's property to this node for the new name value
|
||||
parentmap = parent.getDbMapping ();
|
||||
DbMapping parentmap = parent.getDbMapping ();
|
||||
Relation prel = parentmap.getPropertyRelation ();
|
||||
|
||||
if (prel != null && prel.subnodesAreProperties && propname.equals (prel.getRemoteField())) {
|
||||
|
@ -1414,7 +1400,7 @@ public class Node implements INode, Serializable {
|
|||
parent.unset (oldvalue);
|
||||
parent.addNode (this);
|
||||
// let the node cache know this key's not for this node anymore.
|
||||
nmgr.evictKey (new Key (prel.other, prel.getKeyID (parent, oldvalue)));
|
||||
nmgr.evictKey (new DbKey (prel.other, prel.getKeyID (parent, oldvalue)));
|
||||
}
|
||||
}
|
||||
parent.setNode (value, this);
|
||||
|
@ -1573,7 +1559,7 @@ public class Node implements INode, Serializable {
|
|||
|
||||
// check if the main identity of this node is as a named property
|
||||
// or as an anonymous node in a collection
|
||||
if (n.parentID == null && n.adoptName && !"root".equalsIgnoreCase (n.getPrototype ())) {
|
||||
if (n.parentHandle == null && n.adoptName && !"root".equalsIgnoreCase (n.getPrototype ())) {
|
||||
n.setParent (this);
|
||||
n.name = propname;
|
||||
n.anonymous = false;
|
||||
|
@ -1587,7 +1573,7 @@ public class Node implements INode, Serializable {
|
|||
|
||||
Property prop = (Property) propMap.get (p2);
|
||||
if (prop != null) {
|
||||
if (prop.type == IProperty.NODE && n.getID ().equals (prop.nvalueID)) {
|
||||
if (prop.type == IProperty.NODE && n.equals (prop.getNodeValue ())) {
|
||||
// nothing to do, just clean up locks and return
|
||||
if (state == CLEAN) clearWriteLock ();
|
||||
if (n.state == CLEAN) n.clearWriteLock ();
|
||||
|
@ -1608,10 +1594,10 @@ public class Node implements INode, Serializable {
|
|||
|
||||
// check node in with transactor cache
|
||||
Transactor tx = (Transactor) Thread.currentThread ();
|
||||
tx.visitCleanNode (new Key (nmap, nID), n);
|
||||
tx.visitCleanNode (new DbKey (nmap, nID), n);
|
||||
// if the field is not the primary key of the property, also register it
|
||||
if (rel != null && rel.direction == Relation.DIRECT && !rel.getKeyID(this, p2).equals (nID)) {
|
||||
Key secKey = new Key (rel.other, rel.getKeyID(this, p2));
|
||||
Key secKey = new DbKey (rel.other, rel.getKeyID(this, p2));
|
||||
nmgr.evictKey (secKey);
|
||||
tx.visitCleanNode (secKey, n);
|
||||
}
|
||||
|
@ -1644,21 +1630,21 @@ public class Node implements INode, Serializable {
|
|||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
protected void registerPropLink (INode n) {
|
||||
protected void registerPropLinkFrom (Node n) {
|
||||
if (isRelational ())
|
||||
return;
|
||||
if (proplinks == null)
|
||||
proplinks = new ExternalizableVector ();
|
||||
String plid = n.getID ();
|
||||
if (!proplinks.contains (plid))
|
||||
proplinks.add (n.getID ());
|
||||
Object fromHandle = n.getHandle ();
|
||||
if (!proplinks.contains (fromHandle))
|
||||
proplinks.add (fromHandle);
|
||||
if (state == CLEAN || state == DELETED)
|
||||
markAs (MODIFIED);
|
||||
}
|
||||
|
||||
protected void unregisterPropLink (INode n) {
|
||||
protected void unregisterPropLinkFrom (Node n) {
|
||||
if (proplinks != null)
|
||||
proplinks.remove (n.getID ());
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.NODE_REMOVED));
|
||||
// Server.throwNodeEvent (new NodeEvent (n, NodeEvent.SUBNODE_REMOVED, this));
|
||||
proplinks.remove (n.getHandle ());
|
||||
if (state == CLEAN)
|
||||
markAs (MODIFIED);
|
||||
}
|
||||
|
@ -1716,21 +1702,28 @@ public class Node implements INode, Serializable {
|
|||
return "HopObject " + name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively convert other implementations of INode into helma.objectmodel.db.Node.
|
||||
* Tell whether this node is stored inside a relational db. This doesn't mean
|
||||
* it actually is stored in a relational db, just that it would be, if the node was
|
||||
* persistent
|
||||
*/
|
||||
/* protected Node convert (INode n) {
|
||||
Hashtable ntable = new Hashtable ();
|
||||
Node converted = new Node (n, ntable, false, nmgr);
|
||||
return converted;
|
||||
} */
|
||||
public boolean isRelational () {
|
||||
return dbmap != null && dbmap.isRelational ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively turn node status from TRANSIENT to NEW so that the Transactor will
|
||||
* know it has to insert this node.
|
||||
*/
|
||||
protected void makePersistentCapable () {
|
||||
if (state == TRANSIENT) {
|
||||
state = NEW;
|
||||
id = nmgr.generateID (dbmap);
|
||||
Transactor current = (Transactor) Thread.currentThread ();
|
||||
current.visitNode (this);
|
||||
current.visitCleanNode (this);
|
||||
}
|
||||
for (Enumeration e = getSubnodes (); e.hasMoreElements (); ) {
|
||||
Node n = (Node) e.nextElement ();
|
||||
if (n.state == TRANSIENT)
|
||||
|
@ -1744,12 +1737,6 @@ public class Node implements INode, Serializable {
|
|||
n.makePersistentCapable ();
|
||||
}
|
||||
}
|
||||
if (state == TRANSIENT) {
|
||||
state = NEW;
|
||||
Transactor current = (Transactor) Thread.currentThread ();
|
||||
current.visitNode (this);
|
||||
current.visitCleanNode (this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1775,8 +1762,11 @@ public class Node implements INode, Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void dumpSubnodes () {
|
||||
System.err.println (subnodes);
|
||||
public void dump () {
|
||||
System.err.println ("subnodes: "+subnodes);
|
||||
System.err.println ("properties: "+propMap);
|
||||
System.err.println ("links: "+links);
|
||||
System.err.println ("proplinks: "+proplinks);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue