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:
parent
69428676e5
commit
44e24b29d7
10 changed files with 131 additions and 54 deletions
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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=\"");
|
||||||
|
|
Loading…
Add table
Reference in a new issue