From 44e24b29d781e573f3d6174376ae287abb927c52 Mon Sep 17 00:00:00 2001 From: hns Date: Fri, 4 Jul 2003 12:40:57 +0000 Subject: [PATCH] Merged all changes and fixes in src/helma/objectmodel/* made between helma_1_3_0 and helma_1_3_0_M1 to the helma_1_2 branch. --- src/helma/objectmodel/db/DbKey.java | 29 ++++++++- src/helma/objectmodel/db/DbMapping.java | 10 +--- src/helma/objectmodel/db/Key.java | 8 ++- src/helma/objectmodel/db/MultiKey.java | 29 ++++++++- src/helma/objectmodel/db/Node.java | 68 ++++++++++++---------- src/helma/objectmodel/db/NodeManager.java | 9 ++- src/helma/objectmodel/db/Relation.java | 15 +++-- src/helma/objectmodel/db/Replicator.java | 9 ++- src/helma/objectmodel/db/SyntheticKey.java | 6 ++ src/helma/objectmodel/dom/XmlWriter.java | 2 +- 10 files changed, 131 insertions(+), 54 deletions(-) diff --git a/src/helma/objectmodel/db/DbKey.java b/src/helma/objectmodel/db/DbKey.java index bf7bb5a3..b8d7ddd1 100644 --- a/src/helma/objectmodel/db/DbKey.java +++ b/src/helma/objectmodel/db/DbKey.java @@ -17,6 +17,10 @@ package helma.objectmodel.db; import java.io.Serializable; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; + /** * This is the internal representation of a database key. It is constructed @@ -27,14 +31,16 @@ public final class DbKey implements Key, Serializable { // the name of the prototype which defines the storage of this object. // this is the name of the object's prototype, or one of its ancestors. // If null, the object is stored in the embedded db. - private final String storageName; + private String storageName; // the id that defines this key's object within the above storage space - private final String id; + private String id; // lazily initialized hashcode private transient int hashcode = 0; + static final long serialVersionUID = 1618863960930966588L; + /** * make a key for a persistent Object, describing its datasource and id. */ @@ -116,4 +122,23 @@ public final class DbKey implements Key, Serializable { public String toString() { return (storageName == null) ? ("[" + id + "]") : (storageName + "[" + id + "]"); } + + // We implement write/readObject to set storageName + // to the interned version of the string. + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.writeObject(storageName); + stream.writeObject(id); + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + storageName = (String) stream.readObject(); + id = (String) stream.readObject(); + // if storageName is not null, set it to the interned version + if (storageName != null) { + storageName = storageName.intern(); + } + } + } diff --git a/src/helma/objectmodel/db/DbMapping.java b/src/helma/objectmodel/db/DbMapping.java index 38ca5824..9d6b1433 100644 --- a/src/helma/objectmodel/db/DbMapping.java +++ b/src/helma/objectmodel/db/DbMapping.java @@ -38,7 +38,7 @@ public final class DbMapping implements Updatable { Application app; // prototype name of this mapping - String typename; + private String typename; // properties from where the mapping is read SystemProperties props; @@ -137,13 +137,9 @@ public final class DbMapping implements Updatable { */ public DbMapping(Application app, String typename, SystemProperties props) { this.app = app; - this.typename = typename; - - // create a unique instance of the string. This is useful so + // create a unique instance of the string. This is useful so // we can compare types just by using == instead of equals. - if (typename != null) { - typename = typename.intern(); - } + this.typename = typename == null ? null : typename.intern(); prop2db = new HashMap(); db2prop = new HashMap(); diff --git a/src/helma/objectmodel/db/Key.java b/src/helma/objectmodel/db/Key.java index 850450eb..185eadf4 100644 --- a/src/helma/objectmodel/db/Key.java +++ b/src/helma/objectmodel/db/Key.java @@ -22,24 +22,26 @@ package helma.objectmodel.db; * */ public interface Key { + /** - * + * Get the key's parent key * * @return ... */ public Key getParentKey(); /** - * + * Get the key's ID part * * @return ... */ public String getID(); /** - * + * Get the key's storage id * * @return ... */ public String getStorageName(); + } diff --git a/src/helma/objectmodel/db/MultiKey.java b/src/helma/objectmodel/db/MultiKey.java index 5e72f03e..aece2c58 100644 --- a/src/helma/objectmodel/db/MultiKey.java +++ b/src/helma/objectmodel/db/MultiKey.java @@ -17,6 +17,9 @@ package helma.objectmodel.db; import java.io.Serializable; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; import java.util.Map; /** @@ -31,14 +34,17 @@ public final class MultiKey implements Key, Serializable { // the name of the prototype which defines the storage of this object. // this is the name of the object's prototype, or one of its ancestors. // If null, the object is stored in the embedded db. - private final String storageName; + private String storageName; // the id that defines this key's object within the above storage space - private final Map parts; + private Map parts; // lazily initialized hashcode private transient int hashcode = 0; + static final long serialVersionUID = -9173409137561990089L; + + /** * make a key for a persistent Object, describing its datasource and key parts. */ @@ -121,4 +127,23 @@ public final class MultiKey implements Key, Serializable { public String toString() { return (storageName == null) ? ("[" + parts + "]") : (storageName + "[" + parts + "]"); } + + // We implement write/readObject to set storageName + // to the interned version of the string. + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.writeObject(storageName); + stream.writeObject(parts); + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + storageName = (String) stream.readObject(); + parts = (Map) stream.readObject(); + // if storageName is not null, set it to the interned version + if (storageName != null) { + storageName = storageName.intern(); + } + } + } diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java index 7db843cf..aa8e3669 100644 --- a/src/helma/objectmodel/db/Node.java +++ b/src/helma/objectmodel/db/Node.java @@ -429,8 +429,9 @@ public final class Node implements INode, Serializable { public String getElementName() { // if subnodes are also mounted as properties, try to get the "nice" prop value // instead of the id by turning the anonymous flag off. - if ((parentHandle != null) && - (lastNameCheck < Math.max(dbmap.getLastTypeChange(), lastmodified))) { + long lastmod = Math.max(dbmap.getLastTypeChange(), lastmodified); + if ((parentHandle != null) && (lastNameCheck < lastmod) && + (dbmap != null) && (dbmap.isRelational())) { try { Node p = parentHandle.getNode(nmgr); DbMapping parentmap = p.getDbMapping(); @@ -1648,34 +1649,36 @@ public final class Node implements INode, Serializable { // the property does not exist in our propmap - see if we should create it on the fly, // either because it is mapped to an object from relational database or defined as // collection aka virtual node - if ((prop == null) && (dbmap != null)) { + if (dbmap != null) { + // the explicitly defined property mapping Relation propRel = dbmap.getPropertyRelation(propname); - // if no property relation is defined for this specific property name, - // use the generic property relation, if one is defined. - if (propRel == null) { - propRel = dbmap.getPropertyRelation(); - } - - // so if we have a property relation and it does in fact link to another object... - if ((propRel != null) && (propRel.isCollection() || propRel.isComplexReference())) { - // in some cases we just want to create and set a generic node without consulting - // the NodeManager if it exists: When we get a collection (aka virtual node) - // from a transient node for the first time, or when we get a collection whose - // content objects are stored in the embedded XML data storage. - if ((state == TRANSIENT) && propRel.virtual) { - Node pn = new Node(propname, propRel.getPrototype(), nmgr); - - pn.setDbMapping(propRel.getVirtualMapping()); - pn.setParent(this); - setNode(propname, pn); - prop = (Property) propMap.get(propname); + // property was not found in propmap + if (prop == null) { + // if no property relation is defined for this specific property name, + // use the generic property relation, if one is defined. + if (propRel == null) { + propRel = dbmap.getPropertyRelation(); } - // if this is from relational database only fetch if this node - // is itself persistent. - else if ((state != TRANSIENT) && propRel.createOnDemand()) { - // this may be a relational node stored by property name - // try { + + // so if we have a property relation and it does in fact link to another object... + if ((propRel != null) && (propRel.isCollection() || propRel.isComplexReference())) { + // in some cases we just want to create and set a generic node without consulting + // the NodeManager if it exists: When we get a collection (aka virtual node) + // from a transient node for the first time, or when we get a collection whose + // content objects are stored in the embedded XML data storage. + if ((state == TRANSIENT) && propRel.virtual) { + Node pn = new Node(propname, propRel.getPrototype(), nmgr); + + pn.setDbMapping(propRel.getVirtualMapping()); + pn.setParent(this); + setNode(propname, pn); + prop = (Property) propMap.get(propname); + } + // if this is from relational database only fetch if this node + // is itself persistent. + else if ((state != TRANSIENT) && propRel.createOnDemand()) { + // this may be a relational node stored by property name Node pn = nmgr.getNode(this, propname, propRel); if (pn != null) { @@ -1688,9 +1691,14 @@ public final class Node implements INode, Serializable { prop = new Property(propname, this, pn); } - // } catch (RuntimeException nonode) { - // wasn't a node after all - // } + } + } + } else if (propRel != null && propRel.isVirtual()) { + // prop was found and explicit property relation is collection - + // this is a collection node containing objects stored in the embedded db + INode pn = prop.getNodeValue(); + if (pn != null) { + pn.setDbMapping(propRel.getVirtualMapping()); } } } diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java index a658a22f..4ee19119 100644 --- a/src/helma/objectmodel/db/NodeManager.java +++ b/src/helma/objectmodel/db/NodeManager.java @@ -274,13 +274,16 @@ public final class NodeManager { if (rel.isComplexReference()) { // a key for a complex reference key = new MultiKey(rel.otherType, rel.getKeyParts(home)); - } else if (rel.virtual || (rel.groupby != null) || !rel.usesPrimaryKey()) { + // } else if (rel.virtual || (rel.groupby != null) || !rel.usesPrimaryKey()) { + } else if (rel.createOnDemand()) { // a key for a virtually defined object that's never actually stored in the db - // or a key for an object that represents subobjects grouped by some property, generated on the fly + // or a key for an object that represents subobjects grouped by some property, + // generated on the fly key = new SyntheticKey(home.getKey(), kstr); } else { // if a key for a node from within the DB - // FIXME: This should never apply, since for every relation-based loading Synthetic Keys are used. Right? + // FIXME: This should never apply, since for every relation-based loading + // Synthetic Keys are used. Right? key = new DbKey(rel.otherType, kstr); } diff --git a/src/helma/objectmodel/db/Relation.java b/src/helma/objectmodel/db/Relation.java index eda70d14..c989d551 100644 --- a/src/helma/objectmodel/db/Relation.java +++ b/src/helma/objectmodel/db/Relation.java @@ -149,7 +149,7 @@ public final class Relation { if (otherType == null) { throw new RuntimeException("DbMapping for " + proto + - " not found from " + ownType.typename); + " not found from " + ownType.getTypeName()); } // make sure the type we're referring to is up to date! @@ -370,12 +370,17 @@ public final class Relation { /** * Returns true if the object represented by this Relation has to be - * created dynamically by the Helma objectmodel runtime as a virtual - * node. Virtual nodes are objects which are only generated on demand - * and never stored to a persistent storage. + * created on demand at runtime by the NodeManager. This is true for: + * + * - collection (aka virtual) nodes + * - nodes accessed via accessname + * - group nodes + * - complex reference nodes */ public boolean createOnDemand() { - return virtual || (accessName != null) || (groupby != null) || isComplexReference(); + return virtual || + (otherType.isRelational() && accessName != null) || + (groupby != null) || isComplexReference(); } /** diff --git a/src/helma/objectmodel/db/Replicator.java b/src/helma/objectmodel/db/Replicator.java index 82669f3c..b567923d 100644 --- a/src/helma/objectmodel/db/Replicator.java +++ b/src/helma/objectmodel/db/Replicator.java @@ -69,15 +69,22 @@ public class Replicator implements Runnable { String url = (String) urls.elementAt(i); IReplicationListener listener = (IReplicationListener) Naming.lookup(url); + if (listener == null) { + throw new NullPointerException("Replication listener not bound for URL "+url); + } + listener.replicateCache(currentAdd, currentDelete); if (nmgr.logReplication) { nmgr.app.logEvent("Sent cache replication event: " + - add.size() + " added, " + delete.size() + + currentAdd.size() + " added, " + currentDelete.size() + " deleted"); } } catch (Exception x) { nmgr.app.logEvent("Error sending cache replication event: " + x); + if (nmgr.app.debug()) { + x.printStackTrace(); + } } } } diff --git a/src/helma/objectmodel/db/SyntheticKey.java b/src/helma/objectmodel/db/SyntheticKey.java index a8c88c3f..7704e6dd 100644 --- a/src/helma/objectmodel/db/SyntheticKey.java +++ b/src/helma/objectmodel/db/SyntheticKey.java @@ -25,12 +25,18 @@ import java.io.Serializable; * virtual nodes and groupby nodes. */ public final class SyntheticKey implements Key, Serializable { + + // the parent key private final Key parentKey; + + // the name relative to the parent key private final String name; // lazily initialized hashcode private transient int hashcode = 0; + static final long serialVersionUID = -693454133259421857L; + /** * make a key for a persistent Object, describing its datasource and id. */ diff --git a/src/helma/objectmodel/dom/XmlWriter.java b/src/helma/objectmodel/dom/XmlWriter.java index 52eba849..2c796f7e 100644 --- a/src/helma/objectmodel/dom/XmlWriter.java +++ b/src/helma/objectmodel/dom/XmlWriter.java @@ -420,7 +420,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants { } write("\" name=\""); - write(node.getName()); + write(HtmlEncoder.encodeXml(node.getName())); write("\" prototype=\""); write(getNodePrototype(node)); write("\" created=\"");