Major cleanup all over the helma.objectmodel.db package.
Fixes bug 151. Some optimization in getElementName(). Removed cases where user prototype was treated as a special case.
This commit is contained in:
parent
b052ee89a7
commit
83d997477c
5 changed files with 158 additions and 132 deletions
|
@ -26,8 +26,6 @@ public final class DbMapping implements Updatable {
|
||||||
// prototype name of this mapping
|
// prototype name of this mapping
|
||||||
String typename;
|
String typename;
|
||||||
|
|
||||||
// int version;
|
|
||||||
|
|
||||||
// properties from where the mapping is read
|
// properties from where the mapping is read
|
||||||
SystemProperties props;
|
SystemProperties props;
|
||||||
|
|
||||||
|
@ -42,8 +40,8 @@ public final class DbMapping implements Updatable {
|
||||||
ParentInfo[] parent;
|
ParentInfo[] parent;
|
||||||
|
|
||||||
// Relations describing subnodes and properties.
|
// Relations describing subnodes and properties.
|
||||||
Relation subnodesRel;
|
Relation subRelation;
|
||||||
Relation propertiesRel;
|
Relation propRelation;
|
||||||
|
|
||||||
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
|
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
|
||||||
DbMapping groupbyMapping;
|
DbMapping groupbyMapping;
|
||||||
|
@ -230,17 +228,19 @@ public final class DbMapping implements Updatable {
|
||||||
if (subnodeMapping != null) {
|
if (subnodeMapping != null) {
|
||||||
try {
|
try {
|
||||||
// check if subnode relation already exists. If so, reuse it
|
// check if subnode relation already exists. If so, reuse it
|
||||||
if (subnodesRel == null)
|
if (subRelation == null)
|
||||||
subnodesRel = new Relation (subnodeMapping, "_children", this, props);
|
subRelation = new Relation (subnodeMapping, "_children", this, props);
|
||||||
subnodesRel.update (subnodeMapping, props);
|
subRelation.update (subnodeMapping, props);
|
||||||
if (subnodesRel.accessor != null)
|
// if subnodes are accessed via access name or group name,
|
||||||
propertiesRel = subnodesRel;
|
// the subnode relation is also the property relation.
|
||||||
|
if (subRelation.accessor != null || subRelation.groupby != null)
|
||||||
|
propRelation = subRelation;
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
||||||
// subnodesRel = null;
|
// subRelation = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
subnodesRel = propertiesRel = null;
|
subRelation = propRelation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupbyMapping != null) {
|
if (groupbyMapping != null) {
|
||||||
|
@ -422,8 +422,8 @@ public final class DbMapping implements Updatable {
|
||||||
|
|
||||||
|
|
||||||
public DbMapping getSubnodeMapping () {
|
public DbMapping getSubnodeMapping () {
|
||||||
if (subnodesRel != null)
|
if (subRelation != null)
|
||||||
return subnodesRel.otherType;
|
return subRelation.otherType;
|
||||||
if (parentMapping != null)
|
if (parentMapping != null)
|
||||||
return parentMapping.getSubnodeMapping ();
|
return parentMapping.getSubnodeMapping ();
|
||||||
return null;
|
return null;
|
||||||
|
@ -452,7 +452,7 @@ public final class DbMapping implements Updatable {
|
||||||
* db-mapping with the right relations to create the group-by nodes
|
* db-mapping with the right relations to create the group-by nodes
|
||||||
*/
|
*/
|
||||||
public synchronized DbMapping getGroupbyMapping () {
|
public synchronized DbMapping getGroupbyMapping () {
|
||||||
if (subnodesRel == null || subnodesRel.groupby == null)
|
if (subRelation == null || subRelation.groupby == null)
|
||||||
return null;
|
return null;
|
||||||
if (groupbyMapping == null) {
|
if (groupbyMapping == null) {
|
||||||
initGroupbyMapping ();
|
initGroupbyMapping ();
|
||||||
|
@ -469,38 +469,31 @@ public final class DbMapping implements Updatable {
|
||||||
groupbyMapping = new DbMapping (app);
|
groupbyMapping = new DbMapping (app);
|
||||||
// If a mapping is defined, make the internal mapping inherit from
|
// If a mapping is defined, make the internal mapping inherit from
|
||||||
// the defined named prototype.
|
// the defined named prototype.
|
||||||
if (subnodesRel.groupbyprototype != null)
|
if (subRelation.groupbyPrototype != null)
|
||||||
groupbyMapping.parentMapping = app.getDbMapping (subnodesRel.groupbyprototype);
|
groupbyMapping.parentMapping = app.getDbMapping (subRelation.groupbyPrototype);
|
||||||
groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation ();
|
groupbyMapping.subRelation = subRelation.getGroupbySubnodeRelation ();
|
||||||
if (propertiesRel != null)
|
if (propRelation != null)
|
||||||
groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation ();
|
groupbyMapping.propRelation = propRelation.getGroupbyPropertyRelation ();
|
||||||
else
|
else
|
||||||
groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation ();
|
groupbyMapping.propRelation = subRelation.getGroupbyPropertyRelation ();
|
||||||
groupbyMapping.typename = subnodesRel.groupbyprototype;
|
groupbyMapping.typename = subRelation.groupbyPrototype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public void setPropertyMapping (DbMapping pm) {
|
|
||||||
properties = pm;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* public void setSubnodeRelation (Relation rel) {
|
|
||||||
subnodesRel = rel;
|
|
||||||
} */
|
|
||||||
|
|
||||||
public void setPropertyRelation (Relation rel) {
|
public void setPropertyRelation (Relation rel) {
|
||||||
propertiesRel = rel;
|
propRelation = rel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Relation getSubnodeRelation () {
|
public Relation getSubnodeRelation () {
|
||||||
if (subnodesRel == null && parentMapping != null)
|
if (subRelation == null && parentMapping != null)
|
||||||
return parentMapping.getSubnodeRelation ();
|
return parentMapping.getSubnodeRelation ();
|
||||||
return subnodesRel;
|
return subRelation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Relation getPropertyRelation () {
|
public Relation getPropertyRelation () {
|
||||||
if (propertiesRel == null && parentMapping != null)
|
if (propRelation == null && parentMapping != null)
|
||||||
return parentMapping.getPropertyRelation ();
|
return parentMapping.getPropertyRelation ();
|
||||||
return propertiesRel;
|
return propRelation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Relation getPropertyRelation (String propname) {
|
public Relation getPropertyRelation (String propname) {
|
||||||
|
@ -524,9 +517,9 @@ public final class DbMapping implements Updatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubnodeGroupby () {
|
public String getSubnodeGroupby () {
|
||||||
if (subnodesRel == null && parentMapping != null)
|
if (subRelation == null && parentMapping != null)
|
||||||
return parentMapping.getSubnodeGroupby ();
|
return parentMapping.getSubnodeGroupby ();
|
||||||
return subnodesRel == null ? null : subnodesRel.groupby;
|
return subRelation == null ? null : subRelation.groupby;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIDgen () {
|
public String getIDgen () {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import helma.objectmodel.*;
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
import helma.framework.IPathElement;
|
import helma.framework.IPathElement;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
// import com.workingdogs.village.*;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,7 +153,7 @@ public final class Node implements INode, Serializable {
|
||||||
transient String subnodeRelation = null;
|
transient String subnodeRelation = null;
|
||||||
transient long lastSubnodeFetch = 0;
|
transient long lastSubnodeFetch = 0;
|
||||||
transient long lastSubnodeChange = 0;
|
transient long lastSubnodeChange = 0;
|
||||||
|
transient long lastNameCheck = 0;
|
||||||
transient long lastParentSet = 0;
|
transient long lastParentSet = 0;
|
||||||
|
|
||||||
transient long lastSubnodeCount = 0; // these two are only used
|
transient long lastSubnodeCount = 0; // these two are only used
|
||||||
|
@ -261,11 +260,6 @@ public final class Node implements INode, Serializable {
|
||||||
name = nameField == null ? id : rs.getString (nameField);
|
name = nameField == null ? id : rs.getString (nameField);
|
||||||
if (name == null || name.length() == 0)
|
if (name == null || name.length() == 0)
|
||||||
name = dbmap.getTypeName() + " " + id;
|
name = dbmap.getTypeName() + " " + id;
|
||||||
// set parent for user objects to internal userroot node
|
|
||||||
if ("user".equals (prototype)) {
|
|
||||||
parentHandle = new NodeHandle (new DbKey (null, "1"));
|
|
||||||
anonymous = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
created = lastmodified = System.currentTimeMillis ();
|
created = lastmodified = System.currentTimeMillis ();
|
||||||
|
|
||||||
|
@ -281,25 +275,25 @@ public final class Node implements INode, Serializable {
|
||||||
switch (rel.getColumnType()) {
|
switch (rel.getColumnType()) {
|
||||||
|
|
||||||
case Types.BIT:
|
case Types.BIT:
|
||||||
newprop.setBooleanValue (rs.getBoolean(rel.getDbField()));
|
newprop.setBooleanValue (rs.getBoolean(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.TINYINT:
|
case Types.TINYINT:
|
||||||
case Types.BIGINT:
|
case Types.BIGINT:
|
||||||
case Types.SMALLINT:
|
case Types.SMALLINT:
|
||||||
case Types.INTEGER:
|
case Types.INTEGER:
|
||||||
newprop.setIntegerValue (rs.getLong(rel.getDbField()));
|
newprop.setIntegerValue (rs.getLong(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.REAL:
|
case Types.REAL:
|
||||||
case Types.FLOAT:
|
case Types.FLOAT:
|
||||||
case Types.DOUBLE:
|
case Types.DOUBLE:
|
||||||
newprop.setFloatValue (rs.getDouble(rel.getDbField()));
|
newprop.setFloatValue (rs.getDouble(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.DECIMAL:
|
case Types.DECIMAL:
|
||||||
case Types.NUMERIC:
|
case Types.NUMERIC:
|
||||||
BigDecimal num = rs.getBigDecimal (rel.getDbField());
|
BigDecimal num = rs.getBigDecimal (columns[i]);
|
||||||
if (num == null)
|
if (num == null)
|
||||||
break;
|
break;
|
||||||
if (num.scale() > 0)
|
if (num.scale() > 0)
|
||||||
|
@ -311,20 +305,20 @@ public final class Node implements INode, Serializable {
|
||||||
case Types.LONGVARBINARY:
|
case Types.LONGVARBINARY:
|
||||||
case Types.VARBINARY:
|
case Types.VARBINARY:
|
||||||
case Types.BINARY:
|
case Types.BINARY:
|
||||||
newprop.setStringValue (rs.getString(rel.getDbField()));
|
newprop.setStringValue (rs.getString(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.LONGVARCHAR:
|
case Types.LONGVARCHAR:
|
||||||
case Types.CHAR:
|
case Types.CHAR:
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
case Types.OTHER:
|
case Types.OTHER:
|
||||||
newprop.setStringValue (rs.getString(rel.getDbField()));
|
newprop.setStringValue (rs.getString(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.DATE:
|
case Types.DATE:
|
||||||
case Types.TIME:
|
case Types.TIME:
|
||||||
case Types.TIMESTAMP:
|
case Types.TIMESTAMP:
|
||||||
newprop.setDateValue (rs.getTimestamp(rel.getDbField()));
|
newprop.setDateValue (rs.getTimestamp(columns[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.NULL:
|
case Types.NULL:
|
||||||
|
@ -333,7 +327,7 @@ public final class Node implements INode, Serializable {
|
||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
newprop.setStringValue (rs.getString(rel.getDbField()));
|
newprop.setStringValue (rs.getString(columns[i]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,10 +478,7 @@ 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.
|
||||||
// Work around this for user objects to alsways return a URL like /users/username
|
if (parentHandle != null && lastNameCheck < Math.max (dbmap.getLastTypeChange(), lastmodified)) {
|
||||||
if ("user".equalsIgnoreCase (prototype)) {
|
|
||||||
anonymous = false;
|
|
||||||
} else if (parentHandle != null) {
|
|
||||||
try {
|
try {
|
||||||
Node p = parentHandle.getNode (nmgr);
|
Node p = parentHandle.getNode (nmgr);
|
||||||
DbMapping parentmap = p.getDbMapping ();
|
DbMapping parentmap = p.getDbMapping ();
|
||||||
|
@ -508,6 +499,7 @@ public final class Node implements INode, Serializable {
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
// just fall back to default method
|
// just fall back to default method
|
||||||
}
|
}
|
||||||
|
lastNameCheck = System.currentTimeMillis ();
|
||||||
}
|
}
|
||||||
return anonymous || name == null || name.length() == 0 ? id : name;
|
return anonymous || name == null || name.length() == 0 ? id : name;
|
||||||
}
|
}
|
||||||
|
@ -615,10 +607,13 @@ public final class Node implements INode, Serializable {
|
||||||
* Register a node as parent of the present node. We can't refer to the node directly, so we use
|
* Register a node as parent of the present node. We can't refer to the node directly, so we use
|
||||||
* the ID + DB map combo.
|
* the ID + DB map combo.
|
||||||
*/
|
*/
|
||||||
public void setParent (Node parent) {
|
protected void setParent (Node parent) {
|
||||||
parentHandle = parent == null ? null : parent.getHandle ();
|
parentHandle = parent == null ? null : parent.getHandle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parent handle which can be used to get the actual parent node.
|
||||||
|
*/
|
||||||
public void setParentHandle (NodeHandle parent) {
|
public void setParentHandle (NodeHandle parent) {
|
||||||
parentHandle = parent;
|
parentHandle = parent;
|
||||||
}
|
}
|
||||||
|
@ -679,10 +674,11 @@ public final class Node implements INode, Serializable {
|
||||||
|
|
||||||
// check what's specified in the type.properties for this node.
|
// check what's specified in the type.properties for this node.
|
||||||
ParentInfo[] parentInfo = null;
|
ParentInfo[] parentInfo = null;
|
||||||
if (isRelational () && (lastParentSet < dbmap.getLastTypeChange() || lastParentSet < lastmodified))
|
if (isRelational () && lastParentSet < Math.max (dbmap.getLastTypeChange(), lastmodified))
|
||||||
parentInfo = dbmap.getParentInfo ();
|
parentInfo = dbmap.getParentInfo ();
|
||||||
|
|
||||||
// check if current parent candidate matches presciption, if not, try to get it
|
// check if current parent candidate matches presciption,
|
||||||
|
// if not, try to get one that does.
|
||||||
if (parentInfo != null && state != TRANSIENT) {
|
if (parentInfo != null && state != TRANSIENT) {
|
||||||
for (int i=0; i<parentInfo.length; i++) {
|
for (int i=0; i<parentInfo.length; i++) {
|
||||||
ParentInfo pinfo = parentInfo[i];
|
ParentInfo pinfo = parentInfo[i];
|
||||||
|
@ -693,7 +689,7 @@ public final class Node implements INode, Serializable {
|
||||||
if (rel != null && rel.reftype == Relation.REFERENCE)
|
if (rel != null && rel.reftype == Relation.REFERENCE)
|
||||||
pn = getNode (pinfo.propname, false);
|
pn = getNode (pinfo.propname, false);
|
||||||
// the parent of this node is the app's root node...
|
// the parent of this node is the app's root node...
|
||||||
if (pinfo.isroot && pn == null)
|
if (pn == null && pinfo.isroot)
|
||||||
pn = nmgr.getNode ("0", nmgr.getDbMapping ("root"));
|
pn = nmgr.getNode ("0", nmgr.getDbMapping ("root"));
|
||||||
// if we found a parent node, check if we ought to use a virtual or groupby node as parent
|
// if we found a parent node, check if we ought to use a virtual or groupby node as parent
|
||||||
if (pn != null) {
|
if (pn != null) {
|
||||||
|
@ -1092,11 +1088,6 @@ public final class Node implements INode, Serializable {
|
||||||
// which needs to be unset
|
// which needs to be unset
|
||||||
if (dbmap != null) {
|
if (dbmap != null) {
|
||||||
Relation srel = dbmap.getSubnodeRelation ();
|
Relation srel = dbmap.getSubnodeRelation ();
|
||||||
/*if (srel != null && srel.reftype == Relation.BACKWARD) {
|
|
||||||
Relation backlink = srel.otherType.columnNameToRelation (srel.getRemoteField ());
|
|
||||||
if (backlink != null && id.equals (node.getString (backlink.propName, false)))
|
|
||||||
node.unset (backlink.propName);
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if subnodes are also accessed as properties. If so, also unset the property
|
// check if subnodes are also accessed as properties. If so, also unset the property
|
||||||
|
@ -1349,27 +1340,33 @@ public final class Node implements INode, Serializable {
|
||||||
prop.convertToNodeReference (pmap);
|
prop.convertToNodeReference (pmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the property does not exist in our propmap - see if we can 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 from a relational database or defined as virtual node
|
// either because it is mapped to an object from relational database or defined as
|
||||||
|
// collection aka virtual node
|
||||||
if (prop == null && dbmap != null) {
|
if (prop == null && dbmap != null) {
|
||||||
Relation prel = dbmap.getPropertyRelation (propname);
|
Relation propRel = dbmap.getPropertyRelation (propname);
|
||||||
Relation srel = dbmap.getSubnodeRelation ();
|
// if no property relation is defined for this specific property name,
|
||||||
if (prel == null && srel != null && srel.groupby != null)
|
// use the generic property relation, if one is defined.
|
||||||
prel = srel;
|
if (propRel == null)
|
||||||
if (prel == null)
|
propRel = dbmap.getPropertyRelation ();
|
||||||
prel = dbmap.getPropertyRelation ();
|
// so if we have a property relation and it does in fact link to another object...
|
||||||
if (prel != null) {
|
if (propRel != null && propRel.isCollection ()) {
|
||||||
// if what we want is a virtual node, fetch anyway.
|
// in some cases we just want to create and set a generic node without consulting
|
||||||
if (state == TRANSIENT && prel.virtual) {
|
// the NodeManager if it exists: When we get a collection (aka virtual node)
|
||||||
INode node = new Node (propname, prel.getPrototype (), nmgr);
|
// from a transient node for the first time, or when we get a collection whose
|
||||||
node.setDbMapping (prel.getVirtualMapping ());
|
// content objects are stored in the embedded XML data storage.
|
||||||
|
if (state == TRANSIENT && propRel.virtual) {
|
||||||
|
INode node = new Node (propname, propRel.getPrototype (), nmgr);
|
||||||
|
node.setDbMapping (propRel.getVirtualMapping ());
|
||||||
setNode (propname, node);
|
setNode (propname, node);
|
||||||
prop = (Property) propMap.get (propname);
|
prop = (Property) propMap.get (propname);
|
||||||
// if this is from relational database only fetch if this node is itself persistent.
|
}
|
||||||
} else if (state != TRANSIENT && (prel.virtual || prel.accessor != null || prel.groupby != null)) {
|
// if this is from relational database only fetch if this node
|
||||||
|
// is itself persistent.
|
||||||
|
else if (state != TRANSIENT && propRel.createPropertyOnDemand ()) {
|
||||||
// this may be a relational node stored by property name
|
// this may be a relational node stored by property name
|
||||||
try {
|
try {
|
||||||
Node pn = nmgr.getNode (this, propname, prel);
|
Node pn = nmgr.getNode (this, propname, propRel);
|
||||||
if (pn != null) {
|
if (pn != null) {
|
||||||
if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
|
if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
|
||||||
pn.setParent (this);
|
pn.setParent (this);
|
||||||
|
@ -1391,11 +1388,6 @@ public final class Node implements INode, Serializable {
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public String getString (String propname, String defaultValue, boolean inherit) {
|
|
||||||
String propValue = getString (propname, inherit);
|
|
||||||
return propValue == null ? defaultValue : propValue;
|
|
||||||
} */
|
|
||||||
|
|
||||||
public String getString (String propname, boolean inherit) {
|
public String getString (String propname, boolean inherit) {
|
||||||
// propname = propname.toLowerCase ();
|
// propname = propname.toLowerCase ();
|
||||||
Property prop = getProperty (propname, inherit);
|
Property prop = getProperty (propname, inherit);
|
||||||
|
@ -1493,10 +1485,10 @@ public final class Node implements INode, Serializable {
|
||||||
// check if this node is already registered with the old name; if so, remove it.
|
// 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
|
// then set parent's property to this node for the new name value
|
||||||
DbMapping parentmap = parent.getDbMapping ();
|
DbMapping parentmap = parent.getDbMapping ();
|
||||||
Relation prel = parentmap.getPropertyRelation ();
|
Relation propRel = parentmap.getPropertyRelation ();
|
||||||
String dbcolumn = dbmap.propertyToColumnName (propname);
|
String dbcolumn = dbmap.propertyToColumnName (propname);
|
||||||
|
|
||||||
if (prel != null && prel.accessor != null && prel.accessor.equals (dbcolumn)) {
|
if (propRel != null && propRel.accessor != null && propRel.accessor.equals (dbcolumn)) {
|
||||||
INode n = parent.getNode (value, false);
|
INode n = parent.getNode (value, false);
|
||||||
if (n != null && n != this) {
|
if (n != null && n != this) {
|
||||||
parent.unset (value);
|
parent.unset (value);
|
||||||
|
|
|
@ -25,9 +25,6 @@ public final class NodeHandle implements INodeState, Serializable {
|
||||||
// the node's key
|
// the node's key
|
||||||
private Key key;
|
private Key key;
|
||||||
|
|
||||||
// cached DbMapping
|
|
||||||
private transient DbMapping dbmap;
|
|
||||||
|
|
||||||
static final long serialVersionUID = 3067763116576910931L;
|
static final long serialVersionUID = 3067763116576910931L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,7 +61,8 @@ public final class NodeHandle implements INodeState, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the key for the node described by this handle. This may only be called on persistent Nodes.
|
* Get the key for the node described by this handle.
|
||||||
|
* This may only be called on persistent Nodes.
|
||||||
*/
|
*/
|
||||||
public Key getKey () {
|
public Key getKey () {
|
||||||
if (key == null)
|
if (key == null)
|
||||||
|
@ -73,7 +71,8 @@ public final class NodeHandle implements INodeState, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ID for the node described by this handle. This may only be called on persistent Nodes.
|
* Get the ID for the node described by this handle.
|
||||||
|
* This may only be called on persistent Nodes.
|
||||||
*/
|
*/
|
||||||
public String getID () {
|
public String getID () {
|
||||||
if (key == null)
|
if (key == null)
|
||||||
|
|
|
@ -1067,10 +1067,11 @@ public final class NodeManager {
|
||||||
private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception {
|
private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception {
|
||||||
Node node = null;
|
Node node = null;
|
||||||
|
|
||||||
if (rel.virtual) {
|
if (rel != null && rel.virtual) {
|
||||||
|
if (rel.needsPersistence ())
|
||||||
|
node = (Node) home.createNode (kstr);
|
||||||
|
else
|
||||||
node = new Node (home, kstr, safe, rel.prototype);
|
node = new Node (home, kstr, safe, rel.prototype);
|
||||||
|
|
||||||
if (rel.prototype != null) {
|
if (rel.prototype != null) {
|
||||||
node.setPrototype (rel.prototype);
|
node.setPrototype (rel.prototype);
|
||||||
node.setDbMapping (app.getDbMapping (rel.prototype));
|
node.setDbMapping (app.getDbMapping (rel.prototype));
|
||||||
|
|
|
@ -57,14 +57,13 @@ public final class Relation {
|
||||||
|
|
||||||
String accessor; // db column used to access objects through this relation
|
String accessor; // db column used to access objects through this relation
|
||||||
String order;
|
String order;
|
||||||
String groupbyorder;
|
String groupbyOrder;
|
||||||
String groupby;
|
String groupby;
|
||||||
String prototype;
|
String prototype;
|
||||||
String groupbyprototype;
|
String groupbyPrototype;
|
||||||
String filter;
|
String filter;
|
||||||
int maxSize = 0;
|
int maxSize = 0;
|
||||||
|
|
||||||
// Relation subnoderelation = null; // additional relation used to filter subnodes for virtual nodes
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor makes a copy of an existing relation. Not all fields are copied, just those
|
* This constructor makes a copy of an existing relation. Not all fields are copied, just those
|
||||||
|
@ -156,8 +155,8 @@ public final class Relation {
|
||||||
// FIXME: needs to be synchronized?
|
// FIXME: needs to be synchronized?
|
||||||
if (virtualMapping != null) {
|
if (virtualMapping != null) {
|
||||||
virtualMapping.lastTypeChange = ownType.lastTypeChange;
|
virtualMapping.lastTypeChange = ownType.lastTypeChange;
|
||||||
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
|
virtualMapping.subRelation = getVirtualSubnodeRelation ();
|
||||||
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
|
virtualMapping.propRelation = getVirtualPropertyRelation ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,12 +189,12 @@ public final class Relation {
|
||||||
if (groupby != null && groupby.trim().length() == 0)
|
if (groupby != null && groupby.trim().length() == 0)
|
||||||
groupby = null;
|
groupby = null;
|
||||||
if (groupby != null) {
|
if (groupby != null) {
|
||||||
groupbyorder = props.getProperty (propName+".group.order");
|
groupbyOrder = props.getProperty (propName+".group.order");
|
||||||
if (groupbyorder != null && groupbyorder.trim().length() == 0)
|
if (groupbyOrder != null && groupbyOrder.trim().length() == 0)
|
||||||
groupbyorder = null;
|
groupbyOrder = null;
|
||||||
groupbyprototype = props.getProperty (propName+".group.prototype");
|
groupbyPrototype = props.getProperty (propName+".group.prototype");
|
||||||
if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
|
if (groupbyPrototype != null && groupbyPrototype.trim().length() == 0)
|
||||||
groupbyprototype = null;
|
groupbyPrototype = null;
|
||||||
// aggressive loading and caching is not supported for groupby-nodes
|
// aggressive loading and caching is not supported for groupby-nodes
|
||||||
aggressiveLoading = aggressiveCaching = false;
|
aggressiveLoading = aggressiveCaching = false;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +228,55 @@ public final class Relation {
|
||||||
return reftype == PRIMITIVE;
|
return reftype == PRIMITIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this Relation describes an object reference property
|
||||||
|
*/
|
||||||
|
public boolean isReference () {
|
||||||
|
return reftype == REFERENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this Relation describes a collection object property
|
||||||
|
*/
|
||||||
|
public boolean isCollection () {
|
||||||
|
return reftype == COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell wether the property described by this relation is to be handled as private, i.e.
|
||||||
|
* a change on it should not result in any changed object/collection relations.
|
||||||
|
*/
|
||||||
|
public boolean isPrivate () {
|
||||||
|
return isPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
public boolean createPropertyOnDemand () {
|
||||||
|
return virtual || accessor != null || groupby != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the object represented by this Relation has to be
|
||||||
|
* persisted in the internal db in order to be functional. This is true if
|
||||||
|
* the subnodes contained in this collection are stored in the embedded
|
||||||
|
* database. In this case, the collection itself must also be an ordinary
|
||||||
|
* object stored in the db, since a virtual collection would lose its
|
||||||
|
* its content after restarts.
|
||||||
|
*/
|
||||||
|
public boolean needsPersistence () {
|
||||||
|
if (!virtual)
|
||||||
|
return false;
|
||||||
|
if (prototype == null)
|
||||||
|
return !otherType.isRelational ();
|
||||||
|
DbMapping sub = otherType.getSubnodeMapping ();
|
||||||
|
return sub != null && !sub.isRelational ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the prototype to be used for object reached by this relation
|
* Return the prototype to be used for object reached by this relation
|
||||||
*/
|
*/
|
||||||
|
@ -301,8 +349,8 @@ public final class Relation {
|
||||||
return null;
|
return null;
|
||||||
if (virtualMapping == null) {
|
if (virtualMapping == null) {
|
||||||
virtualMapping = new DbMapping (ownType.app);
|
virtualMapping = new DbMapping (ownType.app);
|
||||||
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
|
virtualMapping.subRelation = getVirtualSubnodeRelation ();
|
||||||
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
|
virtualMapping.propRelation = getVirtualPropertyRelation ();
|
||||||
}
|
}
|
||||||
return virtualMapping;
|
return virtualMapping;
|
||||||
}
|
}
|
||||||
|
@ -316,8 +364,8 @@ public final class Relation {
|
||||||
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
|
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
|
||||||
Relation vr = new Relation (this);
|
Relation vr = new Relation (this);
|
||||||
vr.groupby = groupby;
|
vr.groupby = groupby;
|
||||||
vr.groupbyorder = groupbyorder;
|
vr.groupbyOrder = groupbyOrder;
|
||||||
vr.groupbyprototype = groupbyprototype;
|
vr.groupbyPrototype = groupbyPrototype;
|
||||||
vr.order = order;
|
vr.order = order;
|
||||||
vr.filter = filter;
|
vr.filter = filter;
|
||||||
vr.maxSize = maxSize;
|
vr.maxSize = maxSize;
|
||||||
|
@ -335,8 +383,8 @@ public final class Relation {
|
||||||
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
|
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
|
||||||
Relation vr = new Relation (this);
|
Relation vr = new Relation (this);
|
||||||
vr.groupby = groupby;
|
vr.groupby = groupby;
|
||||||
vr.groupbyorder = groupbyorder;
|
vr.groupbyOrder = groupbyOrder;
|
||||||
vr.groupbyprototype = groupbyprototype;
|
vr.groupbyPrototype = groupbyPrototype;
|
||||||
vr.order = order;
|
vr.order = order;
|
||||||
vr.filter = filter;
|
vr.filter = filter;
|
||||||
vr.maxSize = maxSize;
|
vr.maxSize = maxSize;
|
||||||
|
@ -352,7 +400,7 @@ public final class Relation {
|
||||||
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
|
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
|
||||||
Relation vr = new Relation (this);
|
Relation vr = new Relation (this);
|
||||||
vr.order = order;
|
vr.order = order;
|
||||||
vr.prototype = groupbyprototype;
|
vr.prototype = groupbyPrototype;
|
||||||
vr.filter = filter;
|
vr.filter = filter;
|
||||||
vr.constraints = constraints;
|
vr.constraints = constraints;
|
||||||
vr.addConstraint (new Constraint (null, null, groupby, true));
|
vr.addConstraint (new Constraint (null, null, groupby, true));
|
||||||
|
@ -369,7 +417,7 @@ public final class Relation {
|
||||||
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
|
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
|
||||||
Relation vr = new Relation (this);
|
Relation vr = new Relation (this);
|
||||||
vr.order = order;
|
vr.order = order;
|
||||||
vr.prototype = groupbyprototype;
|
vr.prototype = groupbyPrototype;
|
||||||
vr.filter = filter;
|
vr.filter = filter;
|
||||||
vr.constraints = constraints;
|
vr.constraints = constraints;
|
||||||
vr.addConstraint (new Constraint (null, null, groupby, true));
|
vr.addConstraint (new Constraint (null, null, groupby, true));
|
||||||
|
@ -410,8 +458,8 @@ public final class Relation {
|
||||||
}
|
}
|
||||||
if (groupby != null) {
|
if (groupby != null) {
|
||||||
q.append (" GROUP BY "+groupby);
|
q.append (" GROUP BY "+groupby);
|
||||||
if (useOrder && groupbyorder != null)
|
if (useOrder && groupbyOrder != null)
|
||||||
q.append (" ORDER BY "+groupbyorder);
|
q.append (" ORDER BY "+groupbyOrder);
|
||||||
} else if (useOrder && order != null)
|
} else if (useOrder && order != null)
|
||||||
q.append (" ORDER BY "+order);
|
q.append (" ORDER BY "+order);
|
||||||
return q.toString ();
|
return q.toString ();
|
||||||
|
@ -437,26 +485,19 @@ public final class Relation {
|
||||||
*/
|
*/
|
||||||
public String getOrder () {
|
public String getOrder () {
|
||||||
if (groupby != null)
|
if (groupby != null)
|
||||||
return groupbyorder;
|
return groupbyOrder;
|
||||||
else
|
else
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell wether the property described by this relation is to be handled as readonly/write protected.
|
* Tell wether the property described by this relation is to be handled
|
||||||
|
* as readonly/write protected.
|
||||||
*/
|
*/
|
||||||
public boolean isReadonly () {
|
public boolean isReadonly () {
|
||||||
return readonly;
|
return readonly;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell wether the property described by this relation is to be handled as private, i.e.
|
|
||||||
* a change on it should not result in any changed object/collection relations.
|
|
||||||
*/
|
|
||||||
public boolean isPrivate () {
|
|
||||||
return isPrivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the child node fullfills the constraints defined by this relation.
|
* Check if the child node fullfills the constraints defined by this relation.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue