moved to helma.objectmodel.db Package
This commit is contained in:
parent
c43cc32f5e
commit
6726baa5a7
8 changed files with 0 additions and 2253 deletions
|
@ -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+"]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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+"]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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+"]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue