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.
This commit is contained in:
hns 2003-07-04 12:40:57 +00:00
parent 69428676e5
commit 44e24b29d7
10 changed files with 131 additions and 54 deletions

View file

@ -17,6 +17,10 @@
package helma.objectmodel.db; package helma.objectmodel.db;
import java.io.Serializable; 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 * 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. // 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. // this is the name of the object's prototype, or one of its ancestors.
// If null, the object is stored in the embedded db. // 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 // the id that defines this key's object within the above storage space
private final String id; private String id;
// lazily initialized hashcode // lazily initialized hashcode
private transient int hashcode = 0; private transient int hashcode = 0;
static final long serialVersionUID = 1618863960930966588L;
/** /**
* make a key for a persistent Object, describing its datasource and id. * 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() { public String toString() {
return (storageName == null) ? ("[" + id + "]") : (storageName + "[" + id + "]"); 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();
}
}
} }

View file

@ -38,7 +38,7 @@ public final class DbMapping implements Updatable {
Application app; Application app;
// prototype name of this mapping // prototype name of this mapping
String typename; private String typename;
// properties from where the mapping is read // properties from where the mapping is read
SystemProperties props; SystemProperties props;
@ -137,13 +137,9 @@ public final class DbMapping implements Updatable {
*/ */
public DbMapping(Application app, String typename, SystemProperties props) { public DbMapping(Application app, String typename, SystemProperties props) {
this.app = app; 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. // we can compare types just by using == instead of equals.
if (typename != null) { this.typename = typename == null ? null : typename.intern();
typename = typename.intern();
}
prop2db = new HashMap(); prop2db = new HashMap();
db2prop = new HashMap(); db2prop = new HashMap();

View file

@ -22,24 +22,26 @@ package helma.objectmodel.db;
* *
*/ */
public interface Key { public interface Key {
/** /**
* * Get the key's parent key
* *
* @return ... * @return ...
*/ */
public Key getParentKey(); public Key getParentKey();
/** /**
* * Get the key's ID part
* *
* @return ... * @return ...
*/ */
public String getID(); public String getID();
/** /**
* * Get the key's storage id
* *
* @return ... * @return ...
*/ */
public String getStorageName(); public String getStorageName();
} }

View file

@ -17,6 +17,9 @@
package helma.objectmodel.db; package helma.objectmodel.db;
import java.io.Serializable; import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.util.Map; 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. // 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. // this is the name of the object's prototype, or one of its ancestors.
// If null, the object is stored in the embedded db. // 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 // the id that defines this key's object within the above storage space
private final Map parts; private Map parts;
// lazily initialized hashcode // lazily initialized hashcode
private transient int hashcode = 0; private transient int hashcode = 0;
static final long serialVersionUID = -9173409137561990089L;
/** /**
* make a key for a persistent Object, describing its datasource and key parts. * 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() { public String toString() {
return (storageName == null) ? ("[" + parts + "]") : (storageName + "[" + parts + "]"); 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();
}
}
} }

View file

@ -429,8 +429,9 @@ public final class Node implements INode, Serializable {
public String getElementName() { public String getElementName() {
// if subnodes are also mounted as properties, try to get the "nice" prop value // if subnodes are also mounted as properties, try to get the "nice" prop value
// instead of the id by turning the anonymous flag off. // instead of the id by turning the anonymous flag off.
if ((parentHandle != null) && long lastmod = Math.max(dbmap.getLastTypeChange(), lastmodified);
(lastNameCheck < Math.max(dbmap.getLastTypeChange(), lastmodified))) { if ((parentHandle != null) && (lastNameCheck < lastmod) &&
(dbmap != null) && (dbmap.isRelational())) {
try { try {
Node p = parentHandle.getNode(nmgr); Node p = parentHandle.getNode(nmgr);
DbMapping parentmap = p.getDbMapping(); 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, // 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 // either because it is mapped to an object from relational database or defined as
// collection aka virtual node // collection aka virtual node
if ((prop == null) && (dbmap != null)) { if (dbmap != null) {
// the explicitly defined property mapping
Relation propRel = dbmap.getPropertyRelation(propname); Relation propRel = dbmap.getPropertyRelation(propname);
// if no property relation is defined for this specific property name, // property was not found in propmap
// use the generic property relation, if one is defined. if (prop == null) {
if (propRel == null) { // if no property relation is defined for this specific property name,
propRel = dbmap.getPropertyRelation(); // 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);
} }
// if this is from relational database only fetch if this node
// is itself persistent. // so if we have a property relation and it does in fact link to another object...
else if ((state != TRANSIENT) && propRel.createOnDemand()) { if ((propRel != null) && (propRel.isCollection() || propRel.isComplexReference())) {
// this may be a relational node stored by property name // in some cases we just want to create and set a generic node without consulting
// try { // 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); Node pn = nmgr.getNode(this, propname, propRel);
if (pn != null) { if (pn != null) {
@ -1688,9 +1691,14 @@ public final class Node implements INode, Serializable {
prop = new Property(propname, this, pn); 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());
} }
} }
} }

View file

@ -274,13 +274,16 @@ public final class NodeManager {
if (rel.isComplexReference()) { if (rel.isComplexReference()) {
// a key for a complex reference // a key for a complex reference
key = new MultiKey(rel.otherType, rel.getKeyParts(home)); 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 // 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); key = new SyntheticKey(home.getKey(), kstr);
} else { } else {
// if a key for a node from within the DB // 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); key = new DbKey(rel.otherType, kstr);
} }

View file

@ -149,7 +149,7 @@ public final class Relation {
if (otherType == null) { if (otherType == null) {
throw new RuntimeException("DbMapping for " + proto + 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! // 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 * Returns true if the object represented by this Relation has to be
* created dynamically by the Helma objectmodel runtime as a virtual * created on demand at runtime by the NodeManager. This is true for:
* node. Virtual nodes are objects which are only generated on demand *
* and never stored to a persistent storage. * - collection (aka virtual) nodes
* - nodes accessed via accessname
* - group nodes
* - complex reference nodes
*/ */
public boolean createOnDemand() { public boolean createOnDemand() {
return virtual || (accessName != null) || (groupby != null) || isComplexReference(); return virtual ||
(otherType.isRelational() && accessName != null) ||
(groupby != null) || isComplexReference();
} }
/** /**

View file

@ -69,15 +69,22 @@ public class Replicator implements Runnable {
String url = (String) urls.elementAt(i); String url = (String) urls.elementAt(i);
IReplicationListener listener = (IReplicationListener) Naming.lookup(url); IReplicationListener listener = (IReplicationListener) Naming.lookup(url);
if (listener == null) {
throw new NullPointerException("Replication listener not bound for URL "+url);
}
listener.replicateCache(currentAdd, currentDelete); listener.replicateCache(currentAdd, currentDelete);
if (nmgr.logReplication) { if (nmgr.logReplication) {
nmgr.app.logEvent("Sent cache replication event: " + nmgr.app.logEvent("Sent cache replication event: " +
add.size() + " added, " + delete.size() + currentAdd.size() + " added, " + currentDelete.size() +
" deleted"); " deleted");
} }
} catch (Exception x) { } catch (Exception x) {
nmgr.app.logEvent("Error sending cache replication event: " + x); nmgr.app.logEvent("Error sending cache replication event: " + x);
if (nmgr.app.debug()) {
x.printStackTrace();
}
} }
} }
} }

View file

@ -25,12 +25,18 @@ import java.io.Serializable;
* virtual nodes and groupby nodes. * virtual nodes and groupby nodes.
*/ */
public final class SyntheticKey implements Key, Serializable { public final class SyntheticKey implements Key, Serializable {
// the parent key
private final Key parentKey; private final Key parentKey;
// the name relative to the parent key
private final String name; private final String name;
// lazily initialized hashcode // lazily initialized hashcode
private transient int hashcode = 0; private transient int hashcode = 0;
static final long serialVersionUID = -693454133259421857L;
/** /**
* make a key for a persistent Object, describing its datasource and id. * make a key for a persistent Object, describing its datasource and id.
*/ */

View file

@ -420,7 +420,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
} }
write("\" name=\""); write("\" name=\"");
write(node.getName()); write(HtmlEncoder.encodeXml(node.getName()));
write("\" prototype=\""); write("\" prototype=\"");
write(getNodePrototype(node)); write(getNodePrototype(node));
write("\" created=\""); write("\" created=\"");