moved to helma.objectmodel.db Package

This commit is contained in:
hns 2001-08-20 14:44:09 +00:00
parent c43cc32f5e
commit 6726baa5a7
8 changed files with 0 additions and 2253 deletions

View file

@ -1,139 +0,0 @@
// DbKey.java
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.objectmodel;
import java.io.Serializable;
/**
* This is the internal representation of a database key. It is constructed
* out of the database URL, the table name, the user name and the database
* key of the node and unique within each Helma application. Currently only
* single keys are supported.
*/
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;
// the id that defines this key's object within the above storage space
private final String id;
// the name of the db field this key refers to. A null value means the primary key column is used.
private final String idfield;
/**
* make a key for a persistent Object, describing its datasource and id.
*/
public DbKey (DbMapping dbmap, String id) {
this.id = id;
this.storageName = dbmap == null ? null : dbmap.getStorageTypeName ();
this.idfield = null;
}
/**
* make a key for a persistent Object, describing its datasource and id using something
* else than the primary key column.
*/
public DbKey (DbMapping dbmap, String id, String idfield) {
this.id = id;
this.storageName = dbmap == null ? null : dbmap.getStorageTypeName ();
this.idfield = idfield;
}
public boolean equals (Object what) {
if (what == this)
return true;
try {
DbKey k = (DbKey) what;
return (storageName == k.storageName || storageName.equals (k.storageName)) &&
(idfield == k.idfield || idfield.equals (k.idfield)) &&
(id == k.id || id.equals (k.id));
} catch (Exception x) {
return false;
}
}
public int hashCode () {
return storageName == null ? id.hashCode () : storageName.hashCode() + id.hashCode ();
}
public Key getParentKey () {
return null;
}
public String getStorageName () {
return storageName;
}
public String getID () {
return id;
}
public String getIDField () {
return idfield;
}
public String toString () {
return storageName == null ? "["+id+"]" : storageName+"["+id+"]";
}
}

View file

@ -1,747 +0,0 @@
// DbMapping.java
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.objectmodel;
import helma.framework.core.Application;
import helma.objectmodel.db.WrappedNodeManager;
import helma.util.Updatable;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.sql.*;
import com.workingdogs.village.*;
/**
* A DbMapping describes how a certain type of Nodes is to mapped to a
* relational database table. Basically it consists of a set of JavaScript property-to-
* Database row bindings which are represented by instances of the Relation class.
*/
public class DbMapping implements Updatable {
// DbMappings belong to an application
Application app;
// prototype name of this mapping
String typename;
// properties from where the mapping is read
SystemProperties props;
// name of data source to which this mapping writes
DbSource source;
// name of datasource
String sourceName;
// name of db table
String table;
// list of properties to try for parent
ParentInfo[] parent;
// list of properties to try as skinmanager
String[] skinmgr;
// DbMapping subnodes;
// DbMapping properties;
Relation subnodesRel;
Relation propertiesRel;
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
DbMapping groupbyMapping;
// Map of property names to Relations objects
Hashtable prop2db;
// Map of db columns to Relations objects
Hashtable db2prop;
// db field used as primary key
String idField;
// db field used as object name
String nameField;
// db field used to identify name of prototype to use for object instantiation
String protoField;
// name of parent prototype, if any
String extendsProto;
// dbmapping of parent prototype, if any
DbMapping parentMapping;
boolean inheritsMapping;
// db field that specifies the prototype of an object
String prototypeField;
// descriptor for key generation method
private String idgen;
// remember last key generated for this table
long lastID;
// the (village) schema of the database table
Schema schema = null;
// the (village) keydef of the db table
KeyDef keydef = null;
// timestamp of last modification of the mapping (type.properties)
long lastTypeChange;
// timestamp of last modification of an object of this type
long lastDataChange;
/**
* Create an empty DbMapping
*/
public DbMapping () {
prop2db = new Hashtable ();
db2prop = new Hashtable ();
parent = null;
// subnodes = null;
// properties = null;
idField = "id";
}
/**
* Create a DbMapping from a type.properties property file
*/
public DbMapping (Application app, String typename, SystemProperties props) {
this.app = app;
this.typename = typename;
prop2db = new Hashtable ();
db2prop = new Hashtable ();
parent = null;
// subnodes = null;
// properties = null;
idField = "id";
this.props = props;
update ();
app.putDbMapping (typename, this);
}
/**
* Tell the type manager whether we need update() to be called
*/
public boolean needsUpdate () {
return props.lastModified () != lastTypeChange;
}
/**
* Read the mapping from the Properties. Return true if the properties were changed.
* The read is split in two, this method and the rewire method. The reason is that in order
* for rewire to work, all other db mappings must have been initialized and registered.
*/
public synchronized void update () {
table = props.getProperty ("_tablename");
idgen = props.getProperty ("_idgen");
// see if there is a field which specifies the prototype of objects, if different prototypes
// can be stored in this table
prototypeField = props.getProperty ("_prototypefield");
// see if this prototype extends (inherits from) any other prototype
extendsProto = props.getProperty ("_extends");
sourceName = props.getProperty ("_datasource");
if (sourceName != null) {
source = app.getDbSource (sourceName);
if (source == null) {
app.logEvent ("*** Data Source for prototype "+typename+" does not exist: "+sourceName);
app.logEvent ("*** accessing or storing a "+typename+" object will cause an error.");
}
}
// id field must not be null, default is "id"
idField = props.getProperty ("_id", "id");
nameField = props.getProperty ("_name");
protoField = props.getProperty ("_prototype");
String parentMapping = props.getProperty ("_parent");
if (parentMapping != null) {
// comma-separated list of properties to be used as parent
StringTokenizer st = new StringTokenizer (parentMapping, ",;");
parent = new ParentInfo[st.countTokens()];
for (int i=0; i<parent.length; i++)
parent[i] = new ParentInfo (st.nextToken().trim());
} else
parent = null;
String skm = props.getProperty ("_skinmanager");
if (skm != null) {
StringTokenizer st = new StringTokenizer (skm, ",;");
skinmgr = new String[st.countTokens()];
for (int i=0; i<skinmgr.length; i++)
skinmgr[i] = st.nextToken().trim();
} else
skinmgr = null;
lastTypeChange = props.lastModified ();
// set the cached schema & keydef to null so it's rebuilt the next time around
schema = null;
keydef = null;
}
/**
* This is the second part of the property reading process, called after the first part has been
* completed on all other mappings in this application
*/
public synchronized void rewire () {
if (extendsProto != null) {
parentMapping = app.getDbMapping (extendsProto);
}
// if (table != null && source != null) {
// app.logEvent ("set data source for "+typename+" to "+source);
Hashtable p2d = new Hashtable ();
Hashtable d2p = new Hashtable ();
for (Enumeration e=props.keys(); e.hasMoreElements(); ) {
String propName = (String) e.nextElement ();
try {
if (!propName.startsWith ("_") && propName.indexOf (".") < 0) {
String dbField = props.getProperty (propName);
// check if a relation for this propery already exists. If so, reuse it
Relation rel = propertyToRelation (propName);
if (rel == null)
rel = new Relation (dbField, propName, this, props);
else
rel.update (dbField, props);
p2d.put (propName, rel);
if (rel.localField != null &&
(rel.direction == Relation.PRIMITIVE ||
rel.direction == Relation.FORWARD))
d2p.put (rel.localField, rel);
// app.logEvent ("Mapping "+propName+" -> "+dbField);
}
} catch (Exception x) {
app.logEvent ("Error in type.properties: "+x.getMessage ());
}
}
prop2db = p2d;
db2prop = d2p;
String subnodeMapping = props.getProperty ("_subnodes");
if (subnodeMapping != null) {
try {
// check if subnode relation already exists. If so, reuse it
if (subnodesRel == null)
subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props);
else
subnodesRel.update (subnodeMapping, props);
// if (subnodesRel.isReference ())
// subnodes = subnodesRel.other;
// else
// subnodes = (DbMapping) app.getDbMapping (subnodeMapping);
} catch (Exception x) {
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
// subnodesRel = null;
}
} else
subnodesRel = null;
String propertiesMapping = props.getProperty ("_properties");
if (propertiesMapping != null) {
try {
// check if property relation already exists. If so, reuse it
if (propertiesRel == null)
propertiesRel = new Relation (propertiesMapping, "_properties", this, props);
else
propertiesRel.update (propertiesMapping, props);
// if (propertiesRel.isReference ())
// properties = propertiesRel.other;
// else
// properties = (DbMapping) app.getDbMapping (propertiesMapping);
// take over groupby flag from subnodes, if properties are subnodes
if (propertiesRel.subnodesAreProperties && subnodesRel != null)
propertiesRel.groupby = subnodesRel.groupby;
} catch (Exception x) {
app.logEvent ("Error reading _properties relation for "+typename+": "+x.getMessage ());
// propertiesRel = null;
}
} else
propertiesRel = null;
if (groupbyMapping != null) {
groupbyMapping.subnodesRel = subnodesRel == null ? null : subnodesRel.getGroupbySubnodeRelation ();
groupbyMapping.propertiesRel = propertiesRel == null ? null : propertiesRel.getGroupbyPropertyRelation ();
groupbyMapping.lastTypeChange = this.lastTypeChange;
}
}
public Connection getConnection () throws ClassNotFoundException, SQLException {
// if source was previously not available, check again
if (source == null && sourceName != null)
source = app.getDbSource (sourceName);
if (sourceName == null && parentMapping != null)
return parentMapping.getConnection ();
if (source == null) {
if (sourceName == null)
throw new SQLException ("Tried to get Connection from non-relational embedded data source.");
else
throw new SQLException ("Datasource is not defined: "+sourceName+".");
}
return source.getConnection ();
}
public DbSource getDbSource () {
if (source == null && parentMapping != null)
return parentMapping.getDbSource ();
return source;
}
public String getSourceID () {
if (source == null && parentMapping != null)
return parentMapping.getSourceID ();
return source == null ? "" : source.url;
}
public String getTableName () {
if (source == null && parentMapping != null)
return parentMapping.getTableName ();
return table;
}
public Application getApplication () {
return app;
}
public String getAppName () {
return app.getName();
}
public String getTypeName () {
return typename;
}
public String getExtends () {
return extendsProto;
}
/**
* Get the primary key column name for objects using this mapping.
*/
public String getIDField () {
if (idField == null && parentMapping != null)
return parentMapping.getIDField ();
return idField;
}
/**
* Get the column used for (internal) names of objects of this type.
*/
public String getNameField () {
if (nameField == null && parentMapping != null)
return parentMapping.getNameField ();
return nameField;
}
/**
* Get the column used for names of prototype.
*/
public String getPrototypeField () {
if (protoField == null && parentMapping != null)
return parentMapping.getPrototypeField ();
return protoField;
}
/**
* Translate a database column name to an object property name according to this mapping.
*/
public String columnNameToProperty (String columnName) {
if (table == null && parentMapping != null)
return parentMapping.columnNameToProperty (columnName);
Relation rel = (Relation) db2prop.get (columnName);
if (rel != null && (rel.direction == Relation.PRIMITIVE || rel.direction == Relation.FORWARD))
return rel.propname;
return null;
}
/**
* Translate an object property name to a database column name according to this mapping.
*/
public String propertyToColumnName (String propName) {
if (table == null && parentMapping != null)
return parentMapping.propertyToColumnName (propName);
Relation rel = (Relation) prop2db.get (propName);
if (rel != null && (rel.direction == Relation.PRIMITIVE || rel.direction == Relation.FORWARD))
return rel.localField;
return null;
}
/**
* Translate a database column name to an object property name according to this mapping.
*/
public Relation columnNameToRelation (String columnName) {
if (table == null && parentMapping != null)
return parentMapping.columnNameToRelation (columnName);
return (Relation) db2prop.get (columnName);
}
/**
* Translate an object property name to a database column name according to this mapping.
*/
public Relation propertyToRelation (String propName) {
if (table == null && parentMapping != null)
return parentMapping.propertyToRelation (propName);
return (Relation) prop2db.get (propName);
}
public synchronized ParentInfo[] getParentInfo () {
if (parent == null && parentMapping != null)
return parentMapping.getParentInfo ();
return parent;
}
public String[] getSkinManagers () {
return skinmgr;
}
public DbMapping getSubnodeMapping () {
if (subnodesRel != null)
return subnodesRel.other;
if (parentMapping != null)
return parentMapping.getSubnodeMapping ();
return null;
}
public DbMapping getExactPropertyMapping (String propname) {
if (propname == null)
return null;
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
if (rel == null && parentMapping != null)
return parentMapping.getExactPropertyMapping (propname);
return rel != null ? rel.other : null;
}
public DbMapping getPropertyMapping (String propname) {
if (propname == null) {
if (propertiesRel != null)
return propertiesRel.other;
if (parentMapping != null)
return parentMapping.getPropertyMapping (null);
}
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
if (rel != null) {
// if this is a virtual node, it doesn't have a dbmapping
if (rel.virtual && rel.prototype == null)
return null;
else
return rel.other;
}
if (propertiesRel != null)
return propertiesRel.other;
if (parentMapping != null)
return parentMapping.getPropertyMapping (propname);
return null;
}
public DbMapping getGroupbyMapping () {
if (subnodesRel == null || subnodesRel.groupby == null)
return null;
if (groupbyMapping == null) {
groupbyMapping = new DbMapping ();
groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation ();
if (propertiesRel != null)
groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation ();
else
groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation ();
groupbyMapping.typename = subnodesRel.groupbyprototype;
}
return groupbyMapping;
}
/* public void setPropertyMapping (DbMapping pm) {
properties = pm;
} */
public void setSubnodeRelation (Relation rel) {
subnodesRel = rel;
}
public void setPropertyRelation (Relation rel) {
propertiesRel = rel;
}
public Relation getSubnodeRelation () {
if (subnodesRel == null && parentMapping != null)
return parentMapping.getSubnodeRelation ();
return subnodesRel;
}
public Relation getPropertyRelation () {
if (propertiesRel == null && parentMapping != null)
return parentMapping.getPropertyRelation ();
return propertiesRel;
}
public Relation getPropertyRelation (String propname) {
if (propname == null)
return getPropertyRelation ();
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
if (rel == null && propertiesRel == null && parentMapping != null)
return parentMapping.getPropertyRelation (propname);
return rel != null ? rel : propertiesRel;
}
public String getSubnodeGroupby () {
if (subnodesRel == null && parentMapping != null)
return parentMapping.getSubnodeGroupby ();
return subnodesRel == null ? null : subnodesRel.groupby;
}
public String getIDgen () {
if (idgen == null && parentMapping != null)
return parentMapping.getIDgen ();
return idgen;
}
public WrappedNodeManager getWrappedNodeManager () {
if (app == null)
throw new RuntimeException ("Can't get node manager from internal db mapping");
return app.getWrappedNodeManager ();
}
/**
* Tell whether this data mapping maps to a relational database table. This returns true
* if a datasource is specified, even if it is not a valid one. Otherwise, objects with invalid
* mappings would be stored in the embedded db instead of an error being thrown, which is
* not what we want.
*/
public boolean isRelational () {
if (sourceName != null)
return true;
if (parentMapping != null)
return parentMapping.isRelational ();
return false;
}
/**
* Return a Village Schema object for this DbMapping.
*/
public synchronized Schema getSchema () throws ClassNotFoundException, SQLException, DataSetException {
if (!isRelational ())
throw new SQLException ("Can't get Schema for non-relational data mapping");
if (source == null && parentMapping != null)
return parentMapping.getSchema ();
// Use local variable s to avoid synchronization (schema may be nulled elsewhere)
Schema s = schema;
if (s != null)
return s;
schema = new Schema ().schema (getConnection (), table, "*");
return schema;
}
/**
* Return a Village Schema object for this DbMapping.
*/
public synchronized KeyDef getKeyDef () {
if (!isRelational ())
throw new RuntimeException ("Can't get KeyDef for non-relational data mapping");
if (source == null && parentMapping != null)
return parentMapping.getKeyDef ();
// Use local variable s to avoid synchronization (keydef may be nulled elsewhere)
KeyDef k = keydef;
if (k != null)
return k;
keydef = new KeyDef ().addAttrib (idField);
return keydef;
}
public String toString () {
if (app == null)
return "[unspecified internal DbMapping]";
else
return ("["+app.getName()+"."+typename+"]");
}
public long getLastTypeChange () {
return lastTypeChange;
}
public long getLastDataChange () {
return lastDataChange;
}
public void notifyDataChange () {
lastDataChange = System.currentTimeMillis ();
if (parentMapping != null && source == null)
parentMapping.notifyDataChange ();
}
public synchronized long getNewID (long dbmax) {
if (parentMapping != null && source == null)
return parentMapping.getNewID (dbmax);
lastID = Math.max (dbmax+1, lastID+1);
return lastID;
}
public Hashtable getProp2DB () {
if (table == null && parentMapping != null)
return parentMapping.getProp2DB ();
return prop2db;
}
public Hashtable getDB2Prop () {
if (table == null && parentMapping != null)
return parentMapping.getDB2Prop ();
return db2prop;
}
/**
* Return the name of the prototype which specifies the storage location
* (dbsource + tablename) for this type, or null if it is stored in the embedded
* db.
*/
public String getStorageTypeName () {
if (table == null && parentMapping != null)
return parentMapping.getStorageTypeName ();
return sourceName == null ? null : typename;
}
}

View file

@ -1,121 +0,0 @@
// DbSource.java
// Copyright (c) Hannes Wallnöfer 1999-2000
package helma.objectmodel;
import java.sql.*;
import java.util.Hashtable;
import helma.objectmodel.db.*;
/**
* This class describes a releational data source (URL, driver, user and password).
*/
public class DbSource {
private String name;
private SystemProperties props;
private static SystemProperties defaultProps = null;
protected String url;
private String driver;
protected String user;
private String password;
private long lastRead = 0l;
public DbSource (String name, SystemProperties props) throws ClassNotFoundException {
this.name = name;
this.props = props;
init ();
IServer.getLogger().log ("created db source ["+name+", "+url+", "+driver+", "+user+"]");
}
public Connection getConnection () throws ClassNotFoundException, SQLException {
Transactor tx = (Transactor) Thread.currentThread ();
Connection con = tx.getConnection (this);
boolean fileUpdated = props.lastModified () > lastRead;
if (!fileUpdated && defaultProps != null)
fileUpdated = defaultProps.lastModified () > lastRead;
if (con == null || con.isClosed () || fileUpdated) {
init ();
Class.forName (driver);
con = DriverManager.getConnection (url, user, password);
// If we wanted to use SQL transactions, we'd set autoCommit to
// false here and make commit/rollback invocations in Transactor methods;
IServer.getLogger().log ("Created new Connection to "+url);
tx.registerConnection (this, con);
//////////////////////////////////////////////
/* DatabaseMetaData meta = con.getMetaData ();
ResultSet tables = meta.getCatalogs ();
while (tables.next())
System.err.println ("********* TABLE: "+ tables.getObject (1));
ResultSet types = meta.getTypeInfo ();
while (types.next())
System.err.println ("******* TYPE: "+types.getObject(1) +" - "+types.getObject(2)+" - "+types.getObject(6));
*/
}
return con;
}
private void init () throws ClassNotFoundException {
lastRead = defaultProps == null ? props.lastModified () : Math.max (props.lastModified (), defaultProps.lastModified ());
url = props.getProperty (name+".url");
driver = props.getProperty (name+".driver");
Class.forName (driver);
user = props.getProperty (name+".user");
password = props.getProperty (name+".password");
}
public String getDriverName () {
return driver;
}
public String getName () {
return name;
}
public static void setDefaultProps (SystemProperties props) {
defaultProps = props;
}
}

View file

@ -1,74 +0,0 @@
// Key.java
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.objectmodel;
/**
* This is the interface for the internal representation of an object key.
*
*/
public interface Key {
public Key getParentKey ();
public String getID ();
public String getStorageName ();
}

View file

@ -1,615 +0,0 @@
// Node.java
// Copyright (c) Hannes Wallnöfer 1997-2000
package helma.objectmodel;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Date;
import java.util.StringTokenizer;
import java.io.*;
import helma.util.*;
import helma.framework.IPathElement;
/**
* A transient implementation of INode. An instance of this class can't be
* made persistent by reachability from a persistent node. To make a persistent-capable
* object, class helma.objectmodel.db.Node has to be used.
*/
public class Node implements INode, Serializable {
protected Hashtable propMap, nodeMap;
protected Vector nodes;
protected Node parent;
protected Vector links; // links to this node
protected Vector proplinks; // nodes using this node as property
transient String prototype;
protected String contentType;
protected byte content[];
protected long created;
protected long lastmodified;
protected String id, name;
// is the main identity a named property or an anonymous node in a collection?
protected boolean anonymous = false;
transient DbMapping dbmap;
transient boolean adoptName = true; // little helper to know if this node is being converted
private static long idgen = 0;
public String generateID () {
return "t"+idgen++; // make transient ids differ from persistent ones
}
public Node () {
id = generateID ();
name = id;
created = lastmodified = System.currentTimeMillis ();
}
/**
* Make a new Node object with a given name
*/
public Node (String n) {
id = generateID ();
name = n == null || "".equals (n) ? id : n;
created = lastmodified = System.currentTimeMillis ();
}
public void setDbMapping (DbMapping dbmap) {
this.dbmap = dbmap;
}
public DbMapping getDbMapping () {
return dbmap;
}
/**
* navigation-related
*/
public String getID () {
return id;
}
public boolean isAnonymous () {
return anonymous;
}
public String getName () {
return name;
}
public String getElementName () {
return anonymous ? id : name;
}
public int getState () {
return TRANSIENT;
}
public void setState (int s) {
// state always is TRANSIENT on this kind of node
}
public String getFullName () {
return getFullName (null);
}
public String getFullName (INode root) {
String fullname = "";
String divider = null;
StringBuffer b = new StringBuffer ();
Node p = this;
while (p != null && p.parent != null && p != root) {
if (divider != null)
b.insert (0, divider);
else
divider = "/";
b.insert (0, p.getElementName ());
p = p.parent;
}
return b.toString ();
}
/* public INode[] getPath () {
int pathSize = 1;
INode p = getParent ();
while (p != null) {
pathSize +=1;
p = p.getParent ();
}
INode path[] = new INode[pathSize];
p = this;
for (int i = pathSize-1; i>=0; i--) {
path[i] = p;
p = p.getParent ();
}
return path;
} */
public void setName (String name) {
if (name.indexOf('/') > -1)
throw new RuntimeException ("The name of the node must not contain \"/\".");
if (name == null || name.trim().length() == 0)
this.name = id;
else
this.name = name;
}
public String getPrototype () {
return prototype;
}
public void setPrototype (String proto) {
this.prototype = proto;
}
public INode getParent () {
return parent;
}
/**
* INode-related
*/
public void setSubnodeRelation (String rel) {
throw new RuntimeException ("Can't set subnode relation for non-persistent Node.");
}
public String getSubnodeRelation () {
return null;
}
public int numberOfNodes () {
return nodes == null ? 0 : nodes.size ();
}
public INode addNode (INode elem) {
return addNode (elem, numberOfNodes ());
}
public INode addNode (INode elem, int where) {
if (where < 0 || where > numberOfNodes ())
where = numberOfNodes ();
String n = elem.getName();
if (n.indexOf('/') > -1)
throw new RuntimeException ("The name of a node must not contain \"/\" (slash).");
// IServer.getLogger().log ("adding: "+node+" -- "+node.getContentLength ());
if (nodeMap != null && nodeMap.get (elem.getID ()) != null) {
nodes.removeElement (elem);
where = Math.min (where, numberOfNodes ());
nodes.insertElementAt (elem, where);
return elem;
}
if (nodeMap == null) nodeMap = new Hashtable ();
if (nodes == null) nodes = new Vector ();
nodeMap.put (elem.getID (), elem);
nodes.insertElementAt (elem, where);
if (elem instanceof Node) {
Node node = (Node) elem;
if (node.parent == null) {
node.parent = this;
node.anonymous = true;
}
}
lastmodified = System.currentTimeMillis ();
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, node));
return elem;
}
public INode createNode () {
return createNode (null, 0); // where is ignored since this is an anonymous node
}
public INode createNode (int where) {
return createNode (null, where);
}
public INode createNode (String nm) {
return createNode (nm, numberOfNodes ()); // where is usually ignored (if nm != null)
}
public INode createNode (String nm, int where) {
boolean anon = false;
if (nm == null || "".equals (nm.trim ()))
anon = true;
INode n = new Node (nm);
if (anon)
addNode (n, where);
else
setNode (nm, n);
return n;
}
/**
* register a node that links to this node.
*/
/* protected void registerLink (Node from) {
if (links == null)
links = new Vector ();
if (!links.contains (from))
links.addElement (from);
} */
public IPathElement getParentElement () {
return getParent ();
}
public IPathElement getChildElement (String name) {
return getNode (name, false);
}
public INode getSubnode (String name) {
return getSubnode (name, false);
}
public INode getSubnode (String name, boolean inherit) {
StringTokenizer st = new StringTokenizer (name, "/");
Node retval = this, runner;
while (st.hasMoreTokens () && retval != null) {
runner = retval;
String next = st.nextToken().trim().toLowerCase ();
if ("".equals (next))
retval = this;
else
retval = runner.nodeMap == null ? null : (Node) runner.nodeMap.get (next);
if (retval == null)
retval = (Node) runner.getNode (next, inherit);
if (retval == null && inherit && runner == this && parent != null)
retval = (Node) parent.getSubnode (next, inherit);
}
return retval;
}
public INode getSubnodeAt (int index) {
return nodes == null ? null : (INode) nodes.elementAt (index);
}
public int contains (INode n) {
if (n == null || nodes == null)
return -1;
return nodes.indexOf (n);
}
public boolean remove () {
if (anonymous)
parent.unset (name);
else
parent.removeNode (this);
return true;
}
public void removeNode (INode node) {
// IServer.getLogger().log ("removing: "+ node);
releaseNode (node);
Node n = (Node) node;
if (n.getParent () == this && n.anonymous) {
int l = n.links == null ? 0 : n.links.size (); // notify nodes that link to n that n is going down.
for (int i = 0; i < l; i++) {
Node link = (Node) n.links.elementAt (i);
link.releaseNode (n);
}
if (n.proplinks != null) {
// clean up all nodes that use n as a property
for (Enumeration e1 = n.proplinks.elements (); e1.hasMoreElements (); ) try {
Property p = (Property) e1.nextElement ();
p.node.propMap.remove (p.propname.toLowerCase ());
} catch (Exception ignore) {}
}
/* for (Enumeration e2 = n.properties (); e2.hasMoreElements (); ) {
// tell all nodes that are properties of n that they are no longer used as such
Property p = (Property) n.get ((String) e2.nextElement (), false);
if (p != null && p.type == Property.NODE)
p.unregisterNode ();
} */
// remove all subnodes, giving them a chance to destroy themselves.
Vector v = new Vector (); // removeElement modifies the Vector we are enumerating, so we are extra careful.
for (Enumeration e3 = n.getSubnodes (); e3.hasMoreElements (); ) {
v.addElement (e3.nextElement ());
}
int m = v.size ();
for (int i=0; i<m; i++) {
n.removeNode ((Node) v.elementAt (i));
}
if (n.content != null) {
// IServer.getLogger().log ("destroying content of node "+n.getName ());
// ObjectStore.destroy (n.content);
}
} else {
//
n.links.removeElement (this);
}
}
/**
* "Physically" remove a subnode from the subnodes table.
* the logical stuff necessary for keeping data consistent is done elsewhere (in removeNode).
*/
protected void releaseNode (INode node) {
if (nodes == null || nodeMap == null)
return;
int runner = nodes.indexOf (node);
// this is due to difference between .equals() and ==
while (runner > -1 && nodes.elementAt (runner) != node)
runner = nodes.indexOf (node, Math.min (nodes.size()-1, runner+1));
if (runner > -1)
nodes.removeElementAt (runner);
// nodes.remove (node);
Object what = nodeMap.remove (node.getName ().toLowerCase ());
// Server.throwNodeEvent (new NodeEvent (node, NodeEvent.NODE_REMOVED));
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_REMOVED, node));
lastmodified = System.currentTimeMillis ();
// IServer.getLogger().log ("released node "+node +" from "+this+" oldobj = "+what);
}
public Enumeration getSubnodes () {
return nodes == null ? new Vector ().elements () : nodes.elements ();
}
/**
* property-related
*/
public Enumeration properties () {
return propMap == null ? new EmptyEnumeration () : propMap.keys ();
}
private Property getProperty (String propname, boolean inherit) {
Property prop = propMap == null ? null : (Property) propMap.get (propname);
if (prop == null && inherit && parent != null) {
prop = parent.getProperty (propname, inherit);
}
// check if we have to create a virtual node
if (prop == null && dbmap != null) {
Relation rel = dbmap.getPropertyRelation (propname);
if (rel != null && rel.virtual) {
prop = makeVirtualNode (propname, rel);
}
}
return prop;
}
private Property makeVirtualNode (String propname, Relation rel) {
INode node = new helma.objectmodel.db.Node (rel.propname, rel.prototype, dbmap.getWrappedNodeManager());
// node.setState (TRANSIENT);
// make a db mapping good enough that the virtual node finds its subnodes
DbMapping dbm = new DbMapping ();
dbm.setSubnodeRelation (rel);
dbm.setPropertyRelation (rel);
node.setDbMapping (dbm);
setNode (propname, node);
return (Property) propMap.get (propname);
}
public IProperty get (String propname, boolean inherit) {
propname = propname.toLowerCase ();
return getProperty (propname, inherit);
}
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) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getStringValue ();
} catch (Exception ignore) {}
return null;
}
public long getInteger (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getIntegerValue ();
} catch (Exception ignore) {}
return 0;
}
public double getFloat (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getFloatValue ();
} catch (Exception ignore) {}
return 0.0;
}
public Date getDate (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getDateValue ();
} catch (Exception ignore) {}
return null;
}
public boolean getBoolean (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getBooleanValue ();
} catch (Exception ignore) {}
return false;
}
public INode getNode (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getNodeValue ();
} catch (Exception ignore) {}
return null;
}
public Object getJavaObject (String propname, boolean inherit) {
propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getJavaObjectValue ();
} catch (Exception ignore) {}
return null;
}
// create a property if it doesn't exist for this name
private Property initProperty (String propname) {
if (propMap == null)
propMap = new Hashtable ();
propname = propname.trim ();
String p2 = propname.toLowerCase ();
Property prop = (Property) propMap.get (p2);
if (prop == null) {
prop = new Property (propname, this);
propMap.put (p2, prop);
}
return prop;
}
public void setString (String propname, String value) {
// IServer.getLogger().log ("setting String prop");
Property prop = initProperty (propname);
try {
prop.setStringValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
} catch (java.text.ParseException x) {
throw new RuntimeException ("Fehler beim Parsen des Datum-Strings");
}
lastmodified = System.currentTimeMillis ();
}
public void setInteger (String propname, long value) {
// IServer.getLogger().log ("setting bool prop");
Property prop = initProperty (propname);
prop.setIntegerValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}
public void setFloat (String propname, double value) {
// IServer.getLogger().log ("setting bool prop");
Property prop = initProperty (propname);
prop.setFloatValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}
public void setBoolean (String propname, boolean value) {
// IServer.getLogger().log ("setting bool prop");
Property prop = initProperty (propname);
prop.setBooleanValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}
public void setDate (String propname, Date value) {
// IServer.getLogger().log ("setting date prop");
Property prop = initProperty (propname);
prop.setDateValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}
public void setJavaObject (String propname, Object value) {
// IServer.getLogger().log ("setting date prop");
Property prop = initProperty (propname);
prop.setJavaObjectValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}
public void setNode (String propname, INode value) {
// IServer.getLogger().log ("setting date prop");
Property prop = initProperty (propname);
prop.setNodeValue (value);
// check if the main identity of this node is as a named property
// or as an anonymous node in a collection
if (value instanceof Node) {
Node n = (Node) value;
if (n.parent == null && n.adoptName) {
n.name = propname;
n.parent = this;
n.anonymous = false;
}
}
lastmodified = System.currentTimeMillis ();
}
public void unset (String propname) {
if (propMap == null)
return;
try {
Property p = (Property) propMap.remove (propname.toLowerCase ());
lastmodified = System.currentTimeMillis ();
} catch (Exception ignore) {}
}
/* public String getUrl (INode root, INode users, String tmpname, String rootproto) {
throw new RuntimeException ("HREFs on transient (non-db based) Nodes not supported");
} */
public long lastModified () {
return lastmodified;
}
public long created () {
return created;
}
public String toString () {
return "Node " + name;
}
INode cacheNode;
/**
* Get the cache node for this node. This can be used to store transient cache data per node from Javascript.
*/
public synchronized INode getCacheNode () {
if (cacheNode == null)
cacheNode = new Node();
return cacheNode;
}
}

View file

@ -1,41 +0,0 @@
// ParentInfo.java
// Copyright (c) Hannes Wallnöfer 1999-2000
package helma.objectmodel;
/**
* This class describes a parent relation between releational nodes.
*/
public class ParentInfo {
public final String propname;
public final String virtualname;
public final boolean named;
public final boolean isroot;
public ParentInfo (String desc) {
int n = desc.indexOf ("[named]");
named = n > -1;
String d = named ? desc.substring (0, n) : desc;
int dot = d.indexOf (".");
if (dot > -1) {
propname = d.substring (0, dot).trim();
virtualname = d.substring (dot+1).trim();
} else {
propname = d.trim();
virtualname = null;
}
isroot = "root".equals (propname);
// System.err.println ("created "+this);
}
public String toString () {
return "ParentInfo["+propname+","+virtualname+","+named+"]";
}
}

View file

@ -1,398 +0,0 @@
// Relation.java
// Copyright (c) Hannes Wallnöfer 1997-2000
package helma.objectmodel;
import helma.framework.core.Application;
import java.util.Properties;
/**
* This describes how a property of a persistent Object is stored in a
* relational database table. This can be either a scalar property (string, date, number etc.)
* or a reference to one or more other objects.
*/
public class Relation {
// these constants define different type of property-to-db-mappings
// there is an error in the description of this relation
public final static int INVALID = -1;
// a mapping of a non-object, scalar type
public final static int PRIMITIVE = 0;
// a 1-to-1 relation, i.e. a field in the table is a foreign key to another object
public final static int FORWARD = 1;
// a 1-to-many relation, a field in another table points to objects of this type
public final static int BACKWARD = 2;
// direct mapping is a very powerful feature: objects of some types can be directly accessed
// by one of their properties/db fields.
public final static int DIRECT = 3;
// the DbMapping of the type we come from
public DbMapping home;
// the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation
public DbMapping other;
// if this relation defines a virtual node, we need a DbMapping for these virtual nodes
DbMapping virtualMapping;
public String propname;
protected String localField, remoteField;
public int direction;
public boolean virtual;
public boolean readonly;
public boolean aggressiveLoading;
public boolean aggressiveCaching;
public boolean subnodesAreProperties;
public String order;
public String groupbyorder;
public String groupby;
public String dogroupby;
public String prototype;
public String groupbyprototype;
public String filter;
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
* which are needed in groupby- and virtual nodes defined by this relation.
*/
public Relation (Relation rel) {
this.home = rel.home;
this.other = rel.other;
this.localField = rel.localField;
this.remoteField = rel.remoteField;
this.direction = rel.direction;
this.subnodesAreProperties = rel.subnodesAreProperties;
}
/**
* Reads a relation entry from a line in a properties file.
*/
public Relation (String desc, String propname, DbMapping home, Properties props) {
this.home = home;
this.propname = propname;
other = null;
update (desc, props);
}
public void update (String desc, Properties props) {
Application app = home.getApplication ();
boolean mountpoint = false;
if (desc == null || "".equals (desc.trim ())) {
if (propname != null) {
direction = PRIMITIVE;
localField = propname;
} else {
direction = INVALID;
localField = propname;
}
} else {
desc = desc.trim ();
String descLower = desc.toLowerCase ();
if (descLower.startsWith ("[virtual]")) {
desc = desc.substring (9).trim ();
virtual = true;
} else if (descLower.startsWith ("[collection]")) {
desc = desc.substring (12).trim ();
virtual = true;
} else if (descLower.startsWith ("[mountpoint]")) {
desc = desc.substring (12).trim ();
virtual = true;
mountpoint = true;
} else {
virtual = false;
}
if (descLower.startsWith ("[readonly]")) {
desc = desc.substring (10).trim ();
readonly = true;
} else {
readonly = false;
}
if (desc.indexOf ("<") > -1) {
direction = BACKWARD;
int lt = desc.indexOf ("<");
int dot = desc.indexOf (".");
String otherType = dot < 0 ? desc.substring (lt+1).trim () : desc.substring (lt+1, dot).trim ();
other = app.getDbMapping (otherType);
if (other == null)
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
localField = lt < 0 ? null : desc.substring (0, lt).trim ();
if (mountpoint) prototype = otherType;
} else if (desc.indexOf (">") > -1) {
direction = FORWARD;
int bt = desc.indexOf (">");
int dot = desc.indexOf (".");
String otherType = dot > -1 ? desc.substring (bt+1, dot).trim () : desc.substring (bt+1).trim ();
other = app.getDbMapping (otherType);
if (other == null)
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
localField = desc.substring (0, bt).trim ();
remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
if (mountpoint) prototype = otherType;
} else if (desc.indexOf (".") > -1) {
direction = DIRECT;
int dot = desc.indexOf (".");
String otherType = desc.substring (0, dot).trim ();
other = app.getDbMapping (otherType);
if (other == null)
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
remoteField = desc.substring (dot+1).trim ();
localField = null;
if (mountpoint) prototype = otherType;
} else {
if (virtual) {
direction = DIRECT;
other = app.getDbMapping (desc);
if (other == null)
throw new RuntimeException ("DbMapping for "+desc+" not found from "+home.typename);
remoteField = localField = null;
if (mountpoint) prototype = desc;
} else {
direction = PRIMITIVE;
localField = desc.trim ();
}
}
}
// the following options only apply to object relations
if (direction != PRIMITIVE && direction != INVALID) {
String loading = props.getProperty (propname+".loadmode");
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
String caching = props.getProperty (propname+".cachemode");
aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
// get order property
order = props.getProperty (propname+".order");
if (order != null && order.trim().length() == 0)
order = null;
// get additional filter property
filter = props.getProperty (propname+".filter");
if (filter != null && filter.trim().length() == 0)
filter = null;
// get group by property
groupby = props.getProperty (propname+".groupby");
if (groupby != null && groupby.trim().length() == 0)
groupby = null;
if (groupby != null) {
groupbyorder = props.getProperty (propname+".groupby.order");
if (groupbyorder != null && groupbyorder.trim().length() == 0)
groupbyorder = null;
groupbyprototype = props.getProperty (propname+".groupby.prototype");
if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
groupbyprototype = null;
// aggressive loading and caching is not supported for groupby-nodes
aggressiveLoading = aggressiveCaching = false;
}
// check if subnode condition should be applied for property relations
if ("_properties".equalsIgnoreCase (propname) || virtual) {
String subnodes2props = props.getProperty (propname+".aresubnodes");
subnodesAreProperties = "true".equalsIgnoreCase (subnodes2props);
if (virtual) {
String subnodefilter = props.getProperty (propname+".subnoderelation");
if (subnodefilter != null) {
subnoderelation = new Relation (subnodefilter, propname+".subnoderelation", home, props);
subnoderelation.groupby = groupby;
subnoderelation.order = order;
}
}
// update virtual mapping, if it already exists
if (virtualMapping != null) {
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
virtualMapping.lastTypeChange = home.lastTypeChange;
}
}
}
}
public boolean isReference () {
return direction > PRIMITIVE;
}
public boolean usesPrimaryKey () {
if (other == null)
return false;
if (remoteField == null)
// if remote field is null, it is assumed that it points to the primary key
return true;
return remoteField.equalsIgnoreCase (other.getIDField());
}
public Relation getSubnodeRelation () {
return subnoderelation;
}
/**
* Get the local column name for this relation to use in where clauses of select statements.
* This uses the home node's id as fallback if local field is not specified.
*/
public String getLocalField () {
// only assume local field is primary key if other objects "point" to this object
if (localField == null && direction == BACKWARD)
return home.getIDField ();
return localField;
}
/**
* Return the local field name for updates. This is the same as getLocalField, but does not return the
* primary key name as a fallback.
*/
public String getDbField () {
return localField;
}
/**
* Get the "remote" column name for this relation. Uses the remote node's id as fallback if the remote field is not specified.
*/
public String getRemoteField () {
// only assume remote field is primary key if this relation "points" to an object
if (remoteField == null && direction == FORWARD)
return other.getIDField ();
return remoteField;
}
public DbMapping getVirtualMapping () {
if (!virtual)
return null;
if (virtualMapping == null) {
virtualMapping = new DbMapping ();
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
}
return virtualMapping;
}
/**
* Return a Relation that defines the subnodes of a virtual node.
*/
Relation getVirtualSubnodeRelation () {
if (!virtual)
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
Relation vr = null;
if (subnoderelation != null)
vr = new Relation (subnoderelation);
else
vr = new Relation (this);
vr.groupby = groupby;
vr.groupbyorder = groupbyorder;
vr.groupbyprototype = groupbyprototype;
vr.order = order;
vr.filter = filter;
vr.subnoderelation = subnoderelation;
vr.aggressiveLoading = aggressiveLoading;
vr.aggressiveCaching = aggressiveCaching;
return vr;
}
/**
* Return a Relation that defines the properties of a virtual node.
*/
Relation getVirtualPropertyRelation () {
if (!virtual)
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
Relation vr = new Relation (this);
vr.groupby = groupby;
vr.groupbyorder = groupbyorder;
vr.groupbyprototype = groupbyprototype;
vr.order = order;
vr.filter = filter;
vr.subnoderelation = subnoderelation;
return vr;
}
/**
* Return a Relation that defines the subnodes of a group-by node.
*/
Relation getGroupbySubnodeRelation () {
if (groupby == null)
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
Relation vr = null;
if (subnoderelation != null)
vr = new Relation (subnoderelation);
else
vr = new Relation (this);
vr.order = order;
vr.prototype = groupbyprototype;
vr.filter = filter;
vr.dogroupby = groupby;
return vr;
}
/**
* Return a Relation that defines the properties of a group-by node.
*/
Relation getGroupbyPropertyRelation () {
if (groupby == null)
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
Relation vr = new Relation (this);
vr.order = order;
vr.prototype = groupbyprototype;
vr.filter = filter;
vr.dogroupby = groupby;
return vr;
}
public String toString () {
return "Relation["+home+">"+other+"]";
}
}

View file

@ -1,118 +0,0 @@
// SyntheticKey.java
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.objectmodel;
import java.io.Serializable;
/**
* This is the internal key for an object that is not - or not directly - fetched from a db,
* but derived from another object. This is useful for all kinds of object accessed via a
* symbolic name from another object, like objects mounted via a property name column,
* virtual nodes and groupby nodes.
*/
public final class SyntheticKey implements Key, Serializable {
private final Key parentKey;
private final String name;
/**
* make a key for a persistent Object, describing its datasource and id.
*/
public SyntheticKey (Key key, String name) {
this.parentKey = key;
this.name = name;
}
public boolean equals (Object what) {
if (what == this)
return true;
try {
SyntheticKey k = (SyntheticKey) what;
return parentKey.equals (k.parentKey) &&
(name == k.name || name.equals (k.name));
} catch (Exception x) {
return false;
}
}
public int hashCode () {
return name.hashCode () + parentKey.hashCode ();
}
public Key getParentKey () {
return parentKey;
}
public String getID () {
return name;
}
public String getStorageName () {
return null;
}
public String toString () {
return parentKey+"/"+name;
}
}