diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java
index a85a7cb0..87b87a5f 100644
--- a/src/helma/framework/core/Application.java
+++ b/src/helma/framework/core/Application.java
@@ -13,7 +13,6 @@ import helma.objectmodel.*;
import helma.objectmodel.db.*;
import helma.xmlrpc.*;
import helma.util.*;
-import com.sleepycat.db.DbException;
import java.util.*;
import java.io.*;
import java.net.URLEncoder;
@@ -231,7 +230,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
/**
* Get the application ready to run, initializing the evaluators and type manager.
*/
- public void init () throws DbException, ScriptingException {
+ public void init () throws DatabaseException, ScriptingException {
scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment ();
scriptingEngine.init (this, props);
@@ -317,7 +316,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
// shut down node manager and embedded db
try {
nmgr.shutdown ();
- } catch (DbException dbx) {
+ } catch (DatabaseException dbx) {
System.err.println ("Error shutting down embedded db: "+dbx);
}
diff --git a/src/helma/main/Server.java b/src/helma/main/Server.java
index a1158d2d..5a86ad29 100644
--- a/src/helma/main/Server.java
+++ b/src/helma/main/Server.java
@@ -15,7 +15,6 @@ import helma.framework.*;
import helma.framework.core.*;
import helma.xmlrpc.*;
import helma.util.*;
-import com.sleepycat.db.*;
/**
diff --git a/src/helma/objectmodel/DatabaseException.java b/src/helma/objectmodel/DatabaseException.java
new file mode 100644
index 00000000..dbd794a3
--- /dev/null
+++ b/src/helma/objectmodel/DatabaseException.java
@@ -0,0 +1,49 @@
+// DatabaseException.java
+
+package helma.objectmodel;
+
+
+/**
+ * Thrown on any kind of Database-Error
+ */
+
+public class DatabaseException extends RuntimeException {
+
+ public DatabaseException (String msg) {
+ super (msg);
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/objectmodel/IDatabase.java b/src/helma/objectmodel/IDatabase.java
new file mode 100644
index 00000000..2618d621
--- /dev/null
+++ b/src/helma/objectmodel/IDatabase.java
@@ -0,0 +1,35 @@
+// IDatabase.java
+
+package helma.objectmodel;
+
+import helma.objectmodel.db.IDGenerator;
+import helma.objectmodel.INode;
+
+/**
+ * Interface that is implemented by Database wrappers
+ */
+
+public interface IDatabase {
+
+ // db-related
+ public void shutdown ();
+
+ // id-related
+ public String nextID() throws ObjectNotFoundException;
+ public IDGenerator getIDGenerator (ITransaction transaction) throws Exception;
+ public void saveIDGenerator (ITransaction transaction, IDGenerator idgen) throws Exception;
+
+ // node-related
+ public INode getNode (ITransaction transaction, String key) throws Exception;
+ public void saveNode (ITransaction transaction, String key, INode node) throws Exception;
+ public void deleteNode (ITransaction transaction, String key) throws Exception;
+
+ // transaction-related
+ public ITransaction beginTransaction ();
+ public void commitTransaction (ITransaction transaction) throws DatabaseException;
+ public void abortTransaction (ITransaction transaction) throws DatabaseException;
+
+}
+
+
+
diff --git a/src/helma/objectmodel/ITransaction.java b/src/helma/objectmodel/ITransaction.java
new file mode 100644
index 00000000..1d617a9f
--- /dev/null
+++ b/src/helma/objectmodel/ITransaction.java
@@ -0,0 +1,18 @@
+// ITransaction.java
+
+package helma.objectmodel;
+
+/**
+ * This interface is kept for databases that are able
+ * to run transactions. Transactions were used for the
+ * Berkeley database and might be used in other future
+ * databases, so we leave transactions in.
+ */
+
+public interface ITransaction {
+
+}
+
+
+
+
diff --git a/src/helma/objectmodel/db/DbWrapper.java b/src/helma/objectmodel/db/DbWrapper.java
deleted file mode 100644
index 38435894..00000000
--- a/src/helma/objectmodel/db/DbWrapper.java
+++ /dev/null
@@ -1,292 +0,0 @@
-// DbWrapper.java
-// Copyright (c) Hannes Wallnöfer 1999-2000
-
-
-package helma.objectmodel.db;
-
-import com.sleepycat.db.*;
-import helma.objectmodel.ObjectNotFoundException;
-import java.io.*;
-
-/**
- * A wrapper around a Berkeley embedded database. Used to gracefully handle the case
- * when the native library can not be loaded.
- */
-
-public class DbWrapper {
-
- private boolean loaded, useTransactions;
-
- private Db db;
- DbEnv dbenv;
- final int checkpointPause = 600000; // min. 10 minutes between checkpoints
- volatile long lastCheckpoint = 0;
- volatile long txncount=0;
-
- private File dbBaseDir;
- private NodeManager nmgr;
- private String dbHome;
-
- public DbWrapper (String dbHome, String dbFilename, NodeManager nmgr, boolean useTx) throws DbException {
-
- this.dbHome = dbHome;
- this.nmgr = nmgr;
-
- try {
- dbBaseDir = new File (dbHome);
- if (!dbBaseDir.exists())
- dbBaseDir.mkdirs();
-
- useTransactions = useTx;
-
- int dbInitFlags = Db.DB_CREATE | Db.DB_THREAD | Db.DB_INIT_MPOOL;
- if (useTransactions) {
- dbInitFlags = dbInitFlags | Db.DB_INIT_TXN;
- }
-
- dbenv = new DbEnv (0);
- try {
- dbenv.open (dbHome, dbInitFlags, 0); // for berkeley 3.0, add second parameter (null)
- } catch (FileNotFoundException fnf) {
- // we just created the dirs, so this shouldn't happen
- }
-
- try {
- dbenv.set_error_stream(System.err);
- dbenv.set_errpfx("Sleepycat");
- } catch (Exception e) {
- System.err.println("Error in DbWrapper: "+e.toString());
- }
-
- db = new Db (dbenv, 0);
- try {
- db.upgrade (dbFilename, 0);
- } catch (Exception ignore) {
- // nothing to upgrade, db doesn't exist
- }
-
- try {
- db.open (dbFilename, null, Db.DB_BTREE, Db.DB_CREATE, 0644);
- } catch (FileNotFoundException fnf) {
- // we just created the dirs, so this shouldn't happen
- }
- loaded = true;
-
- } catch (NoClassDefFoundError noclass) {
- nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
- nmgr.app.logEvent ("Reason: "+noclass);
- loaded = false;
- } catch (UnsatisfiedLinkError nolib) {
- nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
- nmgr.app.logEvent ("Reason: "+nolib);
- loaded = false;
- }
-
- }
-
-
- public void shutdown () throws DbException {
- if (loaded) {
- db.close (0);
- // closing the dbenv leads to segfault when app is restarted
- // dbenv.close (0);
- // dbenv.remove (dbHome, Db.DB_FORCE);
- nmgr.app.logEvent ("Closed Berkeley DB");
- }
- }
-
- public DbTxn beginTransaction () throws DbException {
- if (loaded && useTransactions)
- return dbenv.txn_begin (null, 0);
- else
- return null;
- }
-
- public void commitTransaction (DbTxn txn) throws DbException {
- if (txn == null || !loaded || !useTransactions)
- return;
- txn.commit (0);
- if (++txncount%100 == 0 && System.currentTimeMillis()-checkpointPause > lastCheckpoint) {
- // checkpoint transaction logs in time interval specified by server.checkpointPause
- // if there are more then 100 transactions to checkpoint.
- checkpoint ();
- }
- }
-
- public void abortTransaction (DbTxn txn) throws DbException {
- if (txn == null || !loaded || !useTransactions)
- return;
- txn.abort ();
- }
-
- protected void checkpoint () throws DbException {
- if (!loaded || !useTransactions || txncount == 0)
- return;
- long now = System.currentTimeMillis();
- if (now - lastCheckpoint < checkpointPause)
- return;
- dbenv.txn_checkpoint (0, 0, 0); // for berkeley 3.0, remove third 0 parameter
- txncount = 0;
- lastCheckpoint = now;
- nmgr.app.logEvent ("Spent "+(System.currentTimeMillis()-now)+" in checkpoint");
- }
-
- public IDGenerator getIDGenerator (DbTxn txn, String kstr) throws Exception {
- if (loaded)
- return getIDGenFromDB (txn, kstr);
- else
- return getIDGenFromFile (kstr);
- }
-
- public Node getNode (DbTxn txn, String kstr) throws Exception {
- if (loaded)
- return getNodeFromDB (txn, kstr);
- else
- return getNodeFromFile (kstr);
- }
-
- public void save (DbTxn txn, String kstr, Object obj) throws Exception {
- if (loaded)
- saveToDB (txn, kstr, obj);
- else
- saveToFile (kstr, obj);
- }
-
- public void delete (DbTxn txn, String kstr) throws Exception {
- if (loaded)
- deleteFromDB (txn, kstr);
- else
- deleteFromFile (kstr);
- }
-
-
- private IDGenerator getIDGenFromDB (DbTxn txn, String kstr) throws Exception {
- long now = System.currentTimeMillis ();
- byte[] kbuf = kstr.getBytes ();
- Dbt key = new Dbt (kbuf);
- key.set_size (kbuf.length);
- Dbt data = new Dbt ();
- data.set_flags (Db.DB_DBT_MALLOC);
-
- db.get (txn, key, data, 0);
-
- byte[] b = data.get_data ();
- if (b == null)
- throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
-
- IDGenerator idgen = null;
- ByteArrayInputStream bin = new ByteArrayInputStream (b);
- ObjectInputStream oin = new ObjectInputStream (bin);
- idgen = (IDGenerator) oin.readObject ();
-
- oin.close ();
- return idgen;
- }
-
-
- private Node getNodeFromDB (DbTxn txn, String kstr) throws Exception {
- long now = System.currentTimeMillis ();
- byte[] kbuf = kstr.getBytes ();
- Dbt key = new Dbt (kbuf);
- key.set_size (kbuf.length);
- Dbt data = new Dbt ();
- data.set_flags (Db.DB_DBT_MALLOC);
-
- db.get (txn, key, data, 0);
-
- byte[] b = data.get_data ();
- if (b == null)
- throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
-
- Node node = null;
- ByteArrayInputStream bin = new ByteArrayInputStream (b);
- ObjectInputStream oin = new ObjectInputStream (bin);
- node = (Node) oin.readObject ();
- oin.close ();
- return node;
- }
-
-
- private void saveToDB (DbTxn txn, String kstr, Object obj) throws Exception {
- long now = System.currentTimeMillis ();
- byte kbuf[] = kstr.getBytes();
- ByteArrayOutputStream bout = new ByteArrayOutputStream ();
- ObjectOutputStream oout = new ObjectOutputStream (bout);
- oout.writeObject (obj);
- oout.close ();
- byte vbuf[] = bout.toByteArray ();
-
- Dbt key = new Dbt (kbuf);
- key.set_size (kbuf.length);
- Dbt value = new Dbt (vbuf);
- value.set_size (vbuf.length);
-
- db.put (txn, key, value, 0);
- // nmgr.app.logEvent ("saved "+obj+", size = "+vbuf.length);
- }
-
- private void deleteFromDB (DbTxn txn, String kstr) throws Exception {
-
- byte kbuf[] = kstr.getBytes();
-
- Dbt key = new Dbt (kbuf);
- key.set_size (kbuf.length);
-
- db.del (txn, key, 0);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // File based fallback methods
- ///////////////////////////////////////////////////////////////////////////////
-
- private IDGenerator getIDGenFromFile (String kstr) throws Exception {
-
- File f = new File (dbBaseDir, kstr);
-
- if ( ! f.exists() )
- throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
-
- IDGenerator idgen = null;
- FileInputStream bin = new FileInputStream (f);
- ObjectInputStream oin = new ObjectInputStream (bin);
- idgen = (IDGenerator) oin.readObject ();
-
- oin.close ();
- return idgen;
- }
-
-
- private Node getNodeFromFile (String kstr) throws Exception {
-
- File f = new File (dbBaseDir, kstr);
-
- if ( ! f.exists() )
- throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
-
- Node node = null;
- FileInputStream bin = new FileInputStream (f);
- ObjectInputStream oin = new ObjectInputStream (bin);
- node = (Node) oin.readObject ();
- oin.close ();
- return node;
- }
-
-
- private void saveToFile (String kstr, Object obj) throws Exception {
-
- File f = new File (dbBaseDir, kstr);
-
- FileOutputStream bout = new FileOutputStream (f);
- ObjectOutputStream oout = new ObjectOutputStream (bout);
- oout.writeObject (obj);
- oout.close ();
- }
-
- private void deleteFromFile (String kstr) throws Exception {
-
- File f = new File (dbBaseDir, kstr);
- f.delete();
- }
-
-
-}
diff --git a/src/helma/objectmodel/db/IDGenerator.java b/src/helma/objectmodel/db/IDGenerator.java
index ca8ba96c..414b573e 100644
--- a/src/helma/objectmodel/db/IDGenerator.java
+++ b/src/helma/objectmodel/db/IDGenerator.java
@@ -58,7 +58,7 @@ public final class IDGenerator implements Serializable {
/**
* Get the current counter value
*/
- protected long getValue () {
+ public long getValue () {
return counter;
}
diff --git a/src/helma/objectmodel/db/Node.java b/src/helma/objectmodel/db/Node.java
index dfaaabc5..10bbcd5a 100644
--- a/src/helma/objectmodel/db/Node.java
+++ b/src/helma/objectmodel/db/Node.java
@@ -124,6 +124,20 @@ public final class Node implements INode, Serializable {
out.writeObject (prototype);
}
+ /**
+ * used by Xml deserialization
+ */
+ public void setPropMap (Hashtable propMap) {
+ this.propMap = propMap;
+ }
+
+ /**
+ * used by Xml deserialization
+ */
+ public void setSubnodes (List subnodes) {
+ this.subnodes = subnodes;
+}
+
private transient String prototype;
private transient NodeHandle handle;
@@ -164,8 +178,9 @@ public final class Node implements INode, Serializable {
/**
* Creates a new Node with the given name. Only used by NodeManager for "root nodes" and
* not in a Transaction context, which is why we can immediately mark it as CLEAN.
+ * ADD: used by wrapped database to re-create an existing Node.
*/
- protected Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
+ public Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
this.nmgr = nmgr;
this.id = id;
this.name = name == null || "".equals (name) ? id : name;
@@ -176,6 +191,17 @@ public final class Node implements INode, Serializable {
}
+ /**
+ * Constructor used to create a Node with a given name from a wrapped database.
+ */
+ public Node (String name, String id, String prototype, WrappedNodeManager nmgr, long created, long lastmodified) {
+ this (name,id,prototype,nmgr);
+ this.created = created;
+ this.lastmodified = lastmodified;
+ }
+
+
+
/**
* Constructor used for virtual nodes.
*/
@@ -459,6 +485,8 @@ public final class Node implements INode, Serializable {
} else {
anonymous = true;
}
+ } else if (p.contains (this) > -1) {
+ anonymous = true;
}
} catch (Exception ignore) {
// just fall back to default method
@@ -577,6 +605,10 @@ public final class Node implements INode, Serializable {
parentHandle = parent == null ? null : parent.getHandle ();
}
+ public void setParentHandle (NodeHandle parent) {
+ parentHandle = parent;
+ }
+
/**
* This version of setParent additionally marks the node as anonymous or non-anonymous,
* depending on the string argument. This is the version called from the scripting framework,
@@ -1197,6 +1229,10 @@ public final class Node implements INode, Serializable {
return new Enum ();
}
+ public List getSubnodeList() {
+ return subnodes;
+ }
+
private boolean ignoreSubnodeChange () {
// return true if a change in subnodes can be ignored because it is
// stored in the subnodes themselves.
@@ -1233,7 +1269,9 @@ public final class Node implements INode, Serializable {
// return propMap == null ? new Vector ().elements () : propMap.elements ();
}
-
+ public Hashtable getPropMap() {
+ return propMap;
+ }
public IProperty get (String propname, boolean inherit) {
return getProperty (propname, inherit);
diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java
index 0021e732..f2a8d880 100644
--- a/src/helma/objectmodel/db/NodeManager.java
+++ b/src/helma/objectmodel/db/NodeManager.java
@@ -6,7 +6,6 @@ package helma.objectmodel.db;
import helma.util.CacheMap;
import helma.objectmodel.*;
import helma.framework.core.Application;
-import com.sleepycat.db.*;
import java.sql.*;
import java.io.*;
import java.util.*;
@@ -26,7 +25,7 @@ public final class NodeManager {
private Replicator replicator;
- protected DbWrapper db;
+ protected IDatabase db;
protected IDGenerator idgen;
@@ -42,7 +41,7 @@ public final class NodeManager {
* Create a new NodeManager for Application app. An embedded database will be
* created in dbHome if one doesn't already exist.
*/
- public NodeManager (Application app, String dbHome, Properties props) throws DbException {
+ public NodeManager (Application app, String dbHome, Properties props) throws DatabaseException {
this.app = app;
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
// Make actual cache size bigger, since we use it only up to the threshold
@@ -68,7 +67,7 @@ public final class NodeManager {
idBaseValue = Math.max (1l, idBaseValue); // 0 and 1 are reserved for root nodes
} catch (NumberFormatException ignore) {}
- db = new DbWrapper (dbHome, helma.main.Server.dbFilename, this, helma.main.Server.useTransactions);
+ db = new XmlDatabase (dbHome, helma.main.Server.dbFilename, this);
initDb ();
logSql = "true".equalsIgnoreCase(props.getProperty ("logsql"));
@@ -77,44 +76,44 @@ public final class NodeManager {
/**
* Method used to create the root node and id-generator, if they don't exist already.
*/
- public void initDb () throws DbException {
+ public void initDb () throws DatabaseException {
- DbTxn txn = null;
+ ITransaction txn = null;
try {
txn = db.beginTransaction ();
try {
- idgen = db.getIDGenerator (txn, "idgen");
+ idgen = db.getIDGenerator (txn);
if (idgen.getValue() < idBaseValue) {
idgen.setValue (idBaseValue);
- db.save (txn, "idgen", idgen);
+ db.saveIDGenerator (txn, idgen);
}
} catch (ObjectNotFoundException notfound) {
// will start with idBaseValue+1
idgen = new IDGenerator (idBaseValue);
- db.save (txn, "idgen", idgen);
+ db.saveIDGenerator (txn, idgen);
}
// check if we need to set the id generator to a base value
Node node = null;
try {
- node = db.getNode (txn, "0");
+ node = (Node)db.getNode (txn, "0");
node.nmgr = safe;
} catch (ObjectNotFoundException notfound) {
node = new Node ("root", "0", "root", safe);
node.setDbMapping (app.getDbMapping ("root"));
- db.save (txn, node.getID (), node);
+ db.saveNode (txn, node.getID (), node);
registerNode (node); // register node with nodemanager cache
}
try {
- node = db.getNode (txn, "1");
+ node = (Node)db.getNode (txn, "1");
node.nmgr = safe;
} catch (ObjectNotFoundException notfound) {
node = new Node ("users", "1", null, safe);
node.setDbMapping (app.getDbMapping ("__userroot__"));
- db.save (txn, node.getID (), node);
+ db.saveNode (txn, node.getID (), node);
registerNode (node); // register node with nodemanager cache
}
@@ -125,7 +124,7 @@ public final class NodeManager {
try {
db.abortTransaction (txn);
} catch (Exception ignore) {}
- throw (new DbException ("Error initializing db"));
+ throw (new DatabaseException ("Error initializing db"));
}
}
@@ -134,7 +133,7 @@ public final class NodeManager {
* Shut down this node manager. This is called when the application using this
* node manager is stopped.
*/
- public void shutdown () throws DbException {
+ public void shutdown () throws DatabaseException {
db.shutdown ();
if (cache != null) {
synchronized (cache) {
@@ -360,7 +359,7 @@ public final class NodeManager {
* Insert a new node in the embedded database or a relational database table, depending
* on its db mapping.
*/
- public void insertNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
+ public void insertNode (IDatabase db, ITransaction txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("insertNode "+node);
@@ -368,7 +367,7 @@ public final class NodeManager {
DbMapping dbm = node.getDbMapping ();
if (dbm == null || !dbm.isRelational ()) {
- db.save (txn, node.getID (), node);
+ db.saveNode (txn, node.getID (), node);
} else {
app.logEvent ("inserting relational node: "+node.getID ());
TableDataSet tds = null;
@@ -438,7 +437,7 @@ public final class NodeManager {
* Updates a modified node in the embedded db or an external relational database, depending
* on its database mapping.
*/
- public void updateNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
+ public void updateNode (IDatabase db, ITransaction txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("updateNode "+node);
@@ -446,7 +445,7 @@ public final class NodeManager {
DbMapping dbm = node.getDbMapping ();
if (dbm == null || !dbm.isRelational ()) {
- db.save (txn, node.getID (), node);
+ db.saveNode (txn, node.getID (), node);
} else {
TableDataSet tds = null;
@@ -537,7 +536,7 @@ public final class NodeManager {
/**
* Performs the actual deletion of a node from either the embedded or an external SQL database.
*/
- public void deleteNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
+ public void deleteNode (IDatabase db, ITransaction txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("deleteNode "+node);
@@ -545,7 +544,7 @@ public final class NodeManager {
DbMapping dbm = node.getDbMapping ();
if (dbm == null || !dbm.isRelational ()) {
- db.delete (txn, node.getID ());
+ db.deleteNode (txn, node.getID ());
} else {
Statement st = null;
try {
@@ -865,14 +864,14 @@ public final class NodeManager {
// private getNode methods
///////////////////////////////////////////////////////////////////////////////////////
- private Node getNodeByKey (DbTxn txn, DbKey key) throws Exception {
+ private Node getNodeByKey (ITransaction txn, DbKey key) throws Exception {
// Note: Key must be a DbKey, otherwise will not work for relational objects
Node node = null;
DbMapping dbm = app.getDbMapping (key.getStorageName ());
String kstr = key.getID ();
if (dbm == null || !dbm.isRelational ()) {
- node = db.getNode (txn, kstr);
+ node = (Node)db.getNode (txn, kstr);
node.nmgr = safe;
if (node != null && dbm != null)
node.setDbMapping (dbm);
@@ -905,7 +904,7 @@ public final class NodeManager {
return node;
}
- private Node getNodeByRelation (DbTxn txn, Node home, String kstr, Relation rel) throws Exception {
+ private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception {
Node node = null;
if (rel.virtual) {
@@ -922,13 +921,13 @@ public final class NodeManager {
} else if (rel != null && rel.groupby != null) {
node = home.getGroupbySubnode (kstr, false);
if (node == null && (rel.otherType == null || !rel.otherType.isRelational ())) {
- node = db.getNode (txn, kstr);
+ node = (Node)db.getNode (txn, kstr);
node.nmgr = safe;
}
return node;
} else if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
- node = db.getNode (txn, kstr);
+ node = (Node)db.getNode (txn, kstr);
node.nmgr = safe;
node.setDbMapping (rel.otherType);
return node;
diff --git a/src/helma/objectmodel/db/Property.java b/src/helma/objectmodel/db/Property.java
index b7da69c1..5a1f0dfd 100644
--- a/src/helma/objectmodel/db/Property.java
+++ b/src/helma/objectmodel/db/Property.java
@@ -202,14 +202,25 @@ public final class Property implements IProperty, Serializable, Cloneable {
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
-
- // registerNode (value);
+
+ // registerNode (value);
type = NODE;
-
+
nhandle = value.getHandle ();
dirty = true;
}
+ public void setNodeHandle (NodeHandle value) {
+ if (type == NODE)
+ unregisterNode ();
+ if (type == JAVAOBJECT)
+ this.jvalue = null;
+ // registerNode (value);
+ type = NODE;
+ nhandle = value;
+ dirty = true;
+ }
+
public void setJavaObjectValue (Object value) {
if (type == NODE)
unregisterNode ();
diff --git a/src/helma/objectmodel/db/Transactor.java b/src/helma/objectmodel/db/Transactor.java
index 66d2c3d9..a4ea136d 100644
--- a/src/helma/objectmodel/db/Transactor.java
+++ b/src/helma/objectmodel/db/Transactor.java
@@ -9,7 +9,6 @@ import java.sql.*;
import helma.objectmodel.*;
import helma.util.Timer;
import helma.framework.TimeoutException;
-import com.sleepycat.db.*;
/**
* A subclass of thread that keeps track of changed nodes and triggers
@@ -30,7 +29,7 @@ public class Transactor extends Thread {
private volatile boolean killed;
// Transaction for the embedded database
- protected DbTxn txn;
+ protected ITransaction txn;
// Transactions for SQL data sources
protected HashMap sqlCon;
@@ -108,7 +107,7 @@ public class Transactor extends Thread {
public synchronized void begin (String tnm) throws Exception {
if (killed)
- throw new DbException ("Transaction started on killed thread");
+ throw new DatabaseException ("Transaction started on killed thread");
if (active)
abort ();
@@ -171,7 +170,7 @@ public class Transactor extends Thread {
cleannodes.clear ();
if (nmgr.idgen.dirty) {
- nmgr.db.save (txn, "idgen", nmgr.idgen);
+ nmgr.db.saveIDGenerator (txn, nmgr.idgen);
nmgr.idgen.dirty = false;
}
diff --git a/src/helma/objectmodel/db/XmlDatabase.java b/src/helma/objectmodel/db/XmlDatabase.java
new file mode 100644
index 00000000..a7cfec5c
--- /dev/null
+++ b/src/helma/objectmodel/db/XmlDatabase.java
@@ -0,0 +1,95 @@
+package helma.objectmodel.db;
+
+import java.io.*;
+import java.util.Date;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+
+import helma.objectmodel.*;
+import helma.objectmodel.dom.*;
+
+/**
+ * A simple XML-database
+ */
+
+public class XmlDatabase implements IDatabase {
+
+ private String dbHome;
+ private File dbBaseDir;
+ private NodeManager nmgr;
+ private IDGenerator idgen;
+ // character encoding to use when writing files.
+ // use standard encoding by default.
+ private String encoding = null;
+
+ public XmlDatabase (String dbHome, String dbFilename, NodeManager nmgr) throws DatabaseException {
+ this.dbHome = dbHome;
+ this.nmgr = nmgr;
+ dbBaseDir = new File (dbHome);
+ if (!dbBaseDir.exists() && !dbBaseDir.mkdirs() )
+ throw new RuntimeException("Couldn't create DB-directory");
+ }
+
+ public void shutdown () { }
+ public ITransaction beginTransaction () throws DatabaseException { return null; }
+ public void commitTransaction (ITransaction txn) throws DatabaseException { }
+ public void abortTransaction (ITransaction txn) throws DatabaseException { }
+
+ public String nextID() throws ObjectNotFoundException {
+ if (idgen==null) {
+ getIDGenerator(null);
+ }
+ return idgen.newID();
+ }
+
+ public IDGenerator getIDGenerator (ITransaction txn) throws ObjectNotFoundException {
+ File file = new File (dbBaseDir, "idgen.xml");
+ this.idgen = IDGenParser.getIDGenerator(file);
+ return idgen;
+ }
+
+ public void saveIDGenerator (ITransaction txn, IDGenerator idgen) throws Exception {
+ File file = new File (dbBaseDir, "idgen.xml");
+ IDGenParser.saveIDGenerator(idgen,file);
+ this.idgen = idgen;
+ }
+
+ public INode getNode (ITransaction txn, String kstr) throws Exception {
+ File f = new File (dbBaseDir, kstr+".xml");
+ if ( ! f.exists() )
+ throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
+ try {
+ XmlReader reader = new XmlReader (nmgr);
+ Node node = (Node)reader.read (f, null);
+ return node;
+ } catch ( RuntimeException x ) {
+ nmgr.app.logEvent("error reading node from XmlDatbase: " + x.toString() );
+ throw new ObjectNotFoundException(x.toString());
+ }
+ }
+
+ public void saveNode (ITransaction txn, String kstr, INode node) throws Exception {
+ XmlWriter writer = null;
+ File file = new File (dbBaseDir,kstr+".xml");
+ if (encoding != null)
+ writer = new XmlWriter (file, encoding);
+ else
+ writer = new XmlWriter (file);
+ writer.setMaxLevels(1);
+ boolean result = writer.write((Node)node);
+ writer.close();
+ }
+
+ public void deleteNode (ITransaction txn, String kstr) throws Exception {
+ File f = new File (dbBaseDir, kstr+".xml");
+ f.delete();
+ }
+
+ public void setEncoding (String enc) {
+ this.encoding = encoding;
+ }
+
+ public String getEncoding () {
+ return encoding;
+ }
+}
diff --git a/src/helma/objectmodel/dom/IDGenParser.java b/src/helma/objectmodel/dom/IDGenParser.java
new file mode 100644
index 00000000..2f16ee7d
--- /dev/null
+++ b/src/helma/objectmodel/dom/IDGenParser.java
@@ -0,0 +1,37 @@
+package helma.objectmodel.dom;
+
+import java.io.*;
+import java.util.Date;
+import org.w3c.dom.*;
+
+import helma.objectmodel.ObjectNotFoundException;
+import helma.objectmodel.db.IDGenerator;
+
+public class IDGenParser {
+
+ public static IDGenerator getIDGenerator (File file) throws ObjectNotFoundException {
+ if ( ! file.exists() )
+ throw new ObjectNotFoundException ("IDGenerator not found in idgen.xml");
+ try {
+ Document document = XmlUtil.parse(new FileInputStream (file));
+ org.w3c.dom.Element tmp = (Element)document.getDocumentElement().getElementsByTagName("counter").item(0);
+ return new IDGenerator( Long.parseLong (XmlUtil.getTextContent(tmp)) );
+ } catch (Exception e) {
+ throw new ObjectNotFoundException(e.toString());
+ }
+ }
+
+ public static IDGenerator saveIDGenerator (IDGenerator idgen, File file) throws Exception {
+ OutputStreamWriter out = new OutputStreamWriter (new FileOutputStream (file));
+ out.write ("\n");
+ out.write ("\n");
+ out.write ("\n" );
+ out.write ("\n");
+ out.write (" " + idgen.getValue() + "\n");
+ out.write ("\n");
+ out.close ();
+ return idgen;
+ }
+
+}
+
diff --git a/src/helma/objectmodel/dom/XmlConstants.java b/src/helma/objectmodel/dom/XmlConstants.java
index 67e79535..2ab0709d 100644
--- a/src/helma/objectmodel/dom/XmlConstants.java
+++ b/src/helma/objectmodel/dom/XmlConstants.java
@@ -2,7 +2,7 @@ package helma.objectmodel.dom;
public interface XmlConstants {
- public final String NAMESPACE = "http://www.helma.org/";
+ public final String NAMESPACE = "http://www.helma.org/docs/guide/features/database";
public final String DATEFORMAT = "dd.MM.yyyy HH:mm:ss z";
}
diff --git a/src/helma/objectmodel/dom/XmlConverter.java b/src/helma/objectmodel/dom/XmlConverter.java
index 8eb48903..9e51d25a 100644
--- a/src/helma/objectmodel/dom/XmlConverter.java
+++ b/src/helma/objectmodel/dom/XmlConverter.java
@@ -108,6 +108,8 @@ public class XmlConverter implements XmlConstants {
continue;
}
+ // FIXME: handle CDATA!
+
// it's some kind of element (property or child)
if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
diff --git a/src/helma/objectmodel/dom/XmlReader.java b/src/helma/objectmodel/dom/XmlReader.java
index 1ceb7ecb..1ed51888 100644
--- a/src/helma/objectmodel/dom/XmlReader.java
+++ b/src/helma/objectmodel/dom/XmlReader.java
@@ -1,91 +1,95 @@
package helma.objectmodel.dom;
-import java.io.*;
-import java.net.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
import java.text.SimpleDateFormat;
import java.text.ParseException;
-import java.util.*;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
-import javax.xml.parsers.*;
import org.w3c.dom.*;
-import helma.objectmodel.*;
+import helma.objectmodel.INode;
+import helma.objectmodel.db.DbKey;
+import helma.objectmodel.db.ExternalizableVector;
+import helma.objectmodel.db.Node;
+import helma.objectmodel.db.NodeHandle;
+import helma.objectmodel.db.NodeManager;
+import helma.objectmodel.db.Property;
public class XmlReader implements XmlConstants {
- private int offset = 0;
private HashMap convertedNodes;
+ private NodeManager nmgr = null;
- public XmlReader() {
+ public XmlReader () {
+ }
+
+ public XmlReader (NodeManager nmgr) {
+ this.nmgr = nmgr;
}
- public INode read( String desc ) {
- return read(desc, new TransientNode() );
- }
-
- public INode read( String desc, INode helmaNode ) throws RuntimeException {
+ /**
+ * main entry to read an xml-file.
+ */
+ public INode read (File file, INode helmaNode) throws RuntimeException {
try {
- return read( new File(desc), helmaNode );
- } catch ( FileNotFoundException notfound ) {
- throw new RuntimeException( "couldn't find xml-file: " + desc );
- } catch ( IOException ioerror ) {
- throw new RuntimeException( "couldn't read xml: " + desc );
- }
- }
-
- public INode read( File file, INode helmaNode ) throws RuntimeException, FileNotFoundException {
- return read( new FileInputStream(file), helmaNode );
- }
-
- public INode read( InputStream in, INode helmaNode ) throws RuntimeException {
- Document document = XmlUtil.parse(in);
- if ( document!=null && document.getDocumentElement()!=null ) {
- Node tmp = document.getDocumentElement().getFirstChild();
- Element workelement = null;
- while( tmp!=null ) {
- tmp = tmp.getNextSibling();
- if ( tmp.getNodeType()==Node.ELEMENT_NODE ) {
- workelement = (Element) tmp;
- break;
- }
- }
- return startConversion( helmaNode, workelement );
- } else {
+ return read (new FileInputStream(file), helmaNode);
+ } catch (FileNotFoundException notfound) {
+ System.err.println ("couldn't find xml-file: " + file.getAbsolutePath ());
return helmaNode;
}
}
- public INode startConversion( INode helmaNode, Element element ) {
- convertedNodes = new HashMap();
- INode convertedNode = convert(helmaNode, element );
- convertedNodes = null;
- return convertedNode;
+ /**
+ * read an InputStream with xml-content.
+ */
+ public INode read (InputStream in, INode helmaNode) throws RuntimeException {
+ if (helmaNode==null && nmgr==null)
+ throw new RuntimeException ("can't create a new Node without a NodeManager");
+ Document document = XmlUtil.parse (in);
+ Element element = XmlUtil.getFirstElement(document);
+ if (element==null)
+ throw new RuntimeException ("corrupted xml-file");
+
+ if (helmaNode==null) {
+ return convert (element);
+ } else {
+ convertedNodes = new HashMap ();
+ INode convertedNode = convert (element, helmaNode);
+ convertedNodes = null;
+ return convertedNode;
+ }
}
- public INode convert( INode helmaNode, Element element ) {
- offset++;
- String idref = element.getAttributeNS(NAMESPACE, "idref");
- String key = idref + "-" + element.getAttributeNS(NAMESPACE, "prototyperef");
+ /**
+ * convert children of an Element to a given helmaNode
+ */
+ public INode convert (Element element, INode helmaNode) {
+ String idref = element.getAttribute("idref");
+ String key = idref + "-" + element.getAttribute("prototyperef");
if( idref!=null && !idref.equals("") ) {
if( convertedNodes.containsKey(key) ) {
- offset--;
return (INode)convertedNodes.get(key);
}
}
- key = element.getAttributeNS(NAMESPACE, "id") + "-" + element.getAttributeNS(NAMESPACE, "prototype");
+ key = element.getAttribute("id") + "-" + element.getAttribute("prototype");
convertedNodes.put( key, helmaNode );
-
- // FIXME: import id on persistent nodes
- String prototype = element.getAttributeNS(NAMESPACE, "prototype");
+ String prototype = element.getAttribute("prototype");
if( !prototype.equals("") && !prototype.equals("hopobject") ) {
helmaNode.setPrototype( prototype );
}
children(helmaNode, element);
- offset--;
return helmaNode;
}
+ // used by convert(Element,INode)
private INode children( INode helmaNode, Element element ) {
NodeList list = element.getChildNodes();
int len = list.getLength();
@@ -94,16 +98,23 @@ public class XmlReader implements XmlConstants {
try {
childElement = (Element)list.item(i);
} catch( ClassCastException e ) {
- continue;
+ continue; // ignore CDATA, comments etc
}
INode workNode = null;
+
if ( childElement.getTagName().equals("hop:child") ) {
- convert( helmaNode.createNode(null), childElement );
- } else if ( !"".equals(childElement.getAttributeNS(NAMESPACE,"id")) || !"".equals(childElement.getAttributeNS(NAMESPACE,"idref")) ) {
- // we've got an object!
- helmaNode.setNode( childElement.getTagName(), convert( helmaNode.createNode(childElement.getTagName()), childElement ) );
+
+ convert (childElement, helmaNode.createNode(null));
+
+ } else if ( !"".equals(childElement.getAttribute("id")) || !"".equals(childElement.getAttribute("idref")) ) {
+
+ String childTagName = childElement.getTagName();
+ INode newNode = convert (childElement, helmaNode.createNode (childTagName));
+ helmaNode.setNode (childTagName, newNode);
+
} else {
- String type = childElement.getAttribute("hop:type");
+
+ String type = childElement.getAttribute("type");
String key = childElement.getTagName();
String content = XmlUtil.getTextContent(childElement);
if ( type.equals("boolean") ) {
@@ -132,26 +143,101 @@ public class XmlReader implements XmlConstants {
return helmaNode;
}
- /** for testing */
- public static void main ( String args[] ) throws Exception {
- try {
- XmlReader x = new XmlReader ();
- INode node = x.read("test.xml");
- } catch ( Exception e ) {
- System.out.println("exception " + e.toString() );
- throw new RuntimeException(e.toString());
+
+ /**
+ * This is a basic de-serialization method for XML-2-Node conversion.
+ * It reads a Node from a database-like file and should return a Node
+ * that matches exactly the one dumped to that file before.
+ * It only supports persistent-capable Nodes (from objectmodel.db-package).
+ */
+ public helma.objectmodel.db.Node convert (Element element) {
+ // FIXME: this method should use Element.getAttributeNS():
+ // FIXME: do we need the name value or is it retrieved through mappings anyway?
+ String name = element.getAttribute("name");
+// String name = null;
+ String id = element.getAttribute("id");
+ String prototype = element.getAttribute("prototype");
+ if ( "".equals(prototype) )
+ prototype = "hopobject";
+ helma.objectmodel.db.Node helmaNode = null;
+ try {
+ long created = Long.parseLong (element.getAttribute ("created"));
+ long lastmodified = Long.parseLong (element.getAttribute ("lastModified"));
+ helmaNode = new helma.objectmodel.db.Node (name,id,prototype,nmgr.safe,created,lastmodified);
+ } catch ( NumberFormatException e ) {
+ helmaNode = new helma.objectmodel.db.Node (name,id,prototype,nmgr.safe);
}
- }
+ // now loop through all child elements and retrieve properties/subnodes for this node.
+ NodeList list = element.getChildNodes();
+ int len = list.getLength();
+ Hashtable propMap = new Hashtable();
+ List subnodes = new ExternalizableVector();
+ for ( int i=0; i0 )
+ helmaNode.setPropMap (propMap);
+ else
+ helmaNode.setPropMap (null);
+ if ( subnodes.size()>0 )
+ helmaNode.setSubnodes (subnodes);
+ else
+ helmaNode.setSubnodes (null);
+ return helmaNode;
}
-
}
diff --git a/src/helma/objectmodel/dom/XmlUtil.java b/src/helma/objectmodel/dom/XmlUtil.java
index dcabc81c..b28e8810 100644
--- a/src/helma/objectmodel/dom/XmlUtil.java
+++ b/src/helma/objectmodel/dom/XmlUtil.java
@@ -10,6 +10,7 @@ import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@@ -54,6 +55,24 @@ public class XmlUtil {
}
}
+ /**
+ * get first "real" element (ie not the document-rootelement, but the next one
+ */
+ public static Element getFirstElement (Document document) {
+ Element workelement = null;
+ if ( document.getDocumentElement()!=null ) {
+ org.w3c.dom.Node tmp = document.getDocumentElement().getFirstChild();
+ while( tmp!=null ) {
+ tmp = tmp.getNextSibling();
+ if ( tmp.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
+ workelement = (Element) tmp;
+ break;
+ }
+ }
+ }
+ return workelement;
+ }
+
/**
* return the text content of an element
*/
diff --git a/src/helma/objectmodel/dom/XmlWriter.java b/src/helma/objectmodel/dom/XmlWriter.java
index b28b6fa0..ff7bfb6d 100644
--- a/src/helma/objectmodel/dom/XmlWriter.java
+++ b/src/helma/objectmodel/dom/XmlWriter.java
@@ -1,65 +1,97 @@
package helma.objectmodel.dom;
-import java.io.*;
-import java.net.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
import helma.objectmodel.*;
+import helma.objectmodel.INode;
+import helma.objectmodel.IProperty;
+import helma.objectmodel.TransientNode;
+import helma.objectmodel.db.Node;
+import helma.objectmodel.db.DbMapping;
import helma.util.HtmlEncoder;
-public class XmlWriter extends OutputStreamWriter implements XmlConstants {
+public class XmlWriter extends OutputStreamWriter implements XmlConstants {
private final static String LINESEPARATOR = System.getProperty("line.separator");
-
+
private Vector convertedNodes;
private int maxLevels = 3;
-
+
private String indent = " ";
private StringBuffer prefix = new StringBuffer();
private static int fileid;
-
+ private SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
+
+ private boolean dbmode = true;
+
/**
* create ids that can be used for temporary files.
*/
- public static int generateID() {
+ public static int generateID() {
return fileid++;
}
/**
* empty constructor, will use System.out as outputstream.
*/
- public XmlWriter () {
+ public XmlWriter () {
super(System.out);
}
- public XmlWriter (OutputStream out) {
+ public XmlWriter (OutputStream out) {
super(out);
}
- public XmlWriter (String desc) throws FileNotFoundException {
+ public XmlWriter (OutputStream out, String enc) throws UnsupportedEncodingException {
+ super(out, enc);
+ }
+
+ public XmlWriter (String desc) throws FileNotFoundException {
super (new FileOutputStream (desc));
}
- public XmlWriter (File file) throws FileNotFoundException {
+ public XmlWriter (String desc, String enc) throws FileNotFoundException, UnsupportedEncodingException {
+ super (new FileOutputStream (desc), enc);
+ }
+
+ public XmlWriter (File file) throws FileNotFoundException {
super (new FileOutputStream (file));
}
+ public XmlWriter (File file, String enc) throws FileNotFoundException, UnsupportedEncodingException {
+ super (new FileOutputStream (file), enc);
+ }
+
/**
* by default writing only descends 50 levels into the node tree to prevent
* infite loops. number can be changed here.
*/
- public void setMaxLevels (int levels) {
+ public void setMaxLevels (int levels) {
maxLevels = levels;
}
+ public void setDatabaseMode (boolean dbmode) {
+ this.dbmode = dbmode;
+ }
+
/**
* set the number of space chars
*/
- public void setIndent (int ct) {
+ public void setIndent (int ct) {
StringBuffer tmp = new StringBuffer ();
- for ( int i=0; i");
+ String encoding = getEncoding();
+ writeln ("");
writeln ("");
writeln ("" );
write ("maxLevels )
+ public void write (INode node, String name, int level) throws IOException {
+ if (node==null)
return;
prefix.append(indent);
- if ( convertedNodes.contains(node) ) {
+ if ( ++level>maxLevels ) {
writeReferenceTag (node, name);
- } else {
+ prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
+ return;
+ }
+ if ( convertedNodes.contains(node) ) {
+ writeReferenceTag (node, name);
+ } else {
convertedNodes.addElement (node);
writeTagOpen (node,name);
+ if ( node.getParent()!=null ) {
+ writeReferenceTag (node.getParent(),"hop:parent");
+ }
writeProperties (node,level);
writeChildren (node,level);
writeTagClose (node,name);
@@ -104,61 +146,72 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
}
+
+
/**
* loop through properties and print them with their property-name
* as elementname
*/
- private void writeProperties (INode node, int level) throws IOException {
- Enumeration e = node.properties();
- while ( e.hasMoreElements() ) {
+ private void writeProperties (INode node, int level) throws IOException {
+ Enumeration e = null;
+ if ( dbmode==true && node instanceof helma.objectmodel.db.Node ) {
+ // a newly constructed db.Node doesn't have a propMap,
+ // but returns an enumeration of all it's db-mapped properties
+ Hashtable props = ((Node)node).getPropMap();
+ if (props==null)
+ return;
+ e = props.keys();
+ } else {
+ e = node.properties();
+ }
+ while ( e.hasMoreElements() ) {
String key = (String)e.nextElement();
IProperty prop = node.get(key,false);
- if ( prop!=null ) {
+ if ( prop!=null ) {
int type = prop.getType();
- if( type==IProperty.NODE ) {
+ if( type==IProperty.NODE ) {
write (node.getNode(key,false), key, level);
- } else {
+ } else {
writeProperty (node.get(key,false));
}
}
}
}
- public void writeNullProperty (String key) throws IOException {
+ public void writeNullProperty (String key) throws IOException {
write (prefix.toString());
write (indent);
write ("<");
write (key);
- write (" hop:type=\"null\"/>");
+ write (" type=\"null\"/>");
write (LINESEPARATOR);
- }
+ }
/**
- * write a single property, set attribute type according to type,
+ * write a single property, set attribute type according to type,
* apply xml-encoding.
*/
- public void writeProperty (IProperty property) throws IOException {
+ public void writeProperty (IProperty property) throws IOException {
write (prefix.toString());
write (indent);
write ("<");
write (property.getName());
- switch (property.getType()) {
+ switch (property.getType()) {
case IProperty.BOOLEAN:
- write (" hop:type=\"boolean\"");
+ write (" type=\"boolean\"");
break;
case IProperty.FLOAT:
- write (" hop:type=\"float\"");
+ write (" type=\"float\"");
break;
- case IProperty.INTEGER:
- write (" hop:type=\"integer\"");
+ case IProperty.INTEGER:
+ write (" type=\"integer\"");
break;
}
- if ( property.getType()==IProperty.DATE ) {
- write (" hop:type=\"date\"");
- SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
+ if ( property.getType()==IProperty.DATE ) {
+ write (" type=\"date\"");
write (">");
write ( format.format (property.getDateValue()) );
- } else {
+ } else {
write (">");
write ( HtmlEncoder.encodeXml (property.getStringValue()) );
}
@@ -171,9 +224,15 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
/**
* loop through the children-array and print them as
*/
- private void writeChildren (INode node, int level) throws IOException {
+ private void writeChildren (INode node, int level) throws IOException {
+ if ( dbmode==true && node instanceof helma.objectmodel.db.Node ) {
+ Node dbNode = (Node)node;
+ DbMapping smap = dbNode.getDbMapping() == null ? null : dbNode.getDbMapping().getSubnodeMapping ();
+ if (smap != null && smap.isRelational ())
+ return;
+ }
Enumeration e = node.getSubnodes();
- while (e.hasMoreElements()) {
+ while (e.hasMoreElements()) {
INode nextNode = (INode)e.nextElement();
write (nextNode, "hop:child", level);
}
@@ -183,16 +242,22 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* write an opening tag for a node. Include id and prototype, use a
* name if parameter is non-empty.
*/
- public void writeTagOpen (INode node, String name) throws IOException {
+ public void writeTagOpen (INode node, String name) throws IOException {
write (prefix.toString());
write ("<");
write ( (name==null)?"hopobject" : name);
- write (" hop:id=\"");
+ write (" id=\"");
write (getNodeIdentifier(node));
- write ("\" hop:prototype=\"");
+ write ("\" name=\"");
+ write (node.getName());
+ write ("\" prototype=\"");
write (getNodePrototype(node));
- write ("\"");
- write (">");
+ write ("\" created=\"");
+ write (Long.toString(node.created()));
+ write ("\" lastModified=\"");
+ write (Long.toString(node.lastModified()));
+ //FIXME: do we need anonymous-property?
+ write ("\">");
write (LINESEPARATOR);
}
@@ -200,7 +265,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
* write a closing tag for a node
* e.g.
*/
- public void writeTagClose (INode node, String name) throws IOException {
+ public void writeTagClose (INode node, String name) throws IOException {
write (prefix.toString());
write ("");
write ( (name==null)?"hopobject" : name);
@@ -210,16 +275,16 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
/**
* write a tag holding a reference to an element that has
- * been dumped before.
- * e.g.
+ * been written out before.
+ * e.g.
*/
- public void writeReferenceTag (INode node, String name) throws IOException {
+ public void writeReferenceTag (INode node, String name) throws IOException {
write (prefix.toString());
write ("<");
write ( (name==null)?"hopobject" : name);
- write ( " hop:idref=\"");
+ write ( " idref=\"");
write (getNodeIdentifier(node));
- write ("\" hop:prototyperef=\"");
+ write ("\" prototyperef=\"");
write (getNodePrototype(node));
write ("\"");
write ("/>");
@@ -229,10 +294,10 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
/**
* retrieve prototype-string of a node, defaults to "hopobject"
*/
- private String getNodePrototype( INode node ) {
- if ( node.getPrototype()==null || "".equals(node.getPrototype()) ) {
+ private String getNodePrototype( INode node ) {
+ if ( node.getPrototype()==null || "".equals(node.getPrototype()) ) {
return "hopobject";
- } else {
+ } else {
return node.getPrototype();
}
}
@@ -240,12 +305,12 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
/**
* TransientNode produces a different ID each time we call the getID()-method
* this is a workaround and uses hashCode if INode stands for a TransientNode.
- */
- private String getNodeIdentifier( INode node ) {
- try {
+ */
+ private String getNodeIdentifier( INode node ) {
+ try {
TransientNode tmp = (TransientNode)node;
return Integer.toString( tmp.hashCode() );
- } catch ( ClassCastException e ) {
+ } catch ( ClassCastException e ) {
return node.getID();
}
}
@@ -253,7 +318,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
public void writeln(String str) throws IOException {
write (str);
write (LINESEPARATOR);
- }
+ }
}