Cleaned up embedded database code:
Cleaned up IDatabase interface, moved code into XmlDatabase, removed IDGenerator code from NodeManager and Transactor.
This commit is contained in:
parent
d8dc1fc61e
commit
9ef4316dd6
4 changed files with 136 additions and 139 deletions
|
@ -16,89 +16,91 @@
|
||||||
|
|
||||||
package helma.objectmodel;
|
package helma.objectmodel;
|
||||||
|
|
||||||
import helma.objectmodel.INode;
|
import helma.framework.core.Application;
|
||||||
import helma.objectmodel.db.IDGenerator;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that is implemented by Database wrappers
|
* Interface that is implemented by Database wrappers
|
||||||
*/
|
*/
|
||||||
public interface IDatabase {
|
public interface IDatabase {
|
||||||
// db-related
|
|
||||||
|
/**
|
||||||
|
* Initialize the database with the given db directory and application.
|
||||||
|
*
|
||||||
|
* @param dbHome
|
||||||
|
* @param app
|
||||||
|
*/
|
||||||
|
public void init(File dbHome, Application app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let the database know we're shutting down.
|
||||||
|
*/
|
||||||
public void shutdown();
|
public void shutdown();
|
||||||
|
|
||||||
// id-related
|
/**
|
||||||
|
* Get the next ID from the db's ID generator
|
||||||
|
* @return a unique id
|
||||||
|
* @throws ObjectNotFoundException
|
||||||
|
*/
|
||||||
public String nextID() throws ObjectNotFoundException;
|
public String nextID() throws ObjectNotFoundException;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param transaction ...
|
|
||||||
*
|
|
||||||
* @return ...
|
|
||||||
*
|
|
||||||
* @throws IOException ...
|
|
||||||
*/
|
|
||||||
public IDGenerator getIDGenerator(ITransaction transaction)
|
|
||||||
throws IOException, ObjectNotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Get the node from the database specified by the given key.
|
||||||
*
|
*
|
||||||
*
|
* @param transaction
|
||||||
* @param transaction ...
|
* @param key
|
||||||
* @param idgen ...
|
* @return
|
||||||
*
|
* @throws IOException
|
||||||
* @throws IOException ...
|
* @throws ObjectNotFoundException if no object exists for the key.
|
||||||
*/
|
*/
|
||||||
public void saveIDGenerator(ITransaction transaction, IDGenerator idgen)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
// node-related
|
|
||||||
public INode getNode(ITransaction transaction, String key)
|
public INode getNode(ITransaction transaction, String key)
|
||||||
throws IOException, ObjectNotFoundException;
|
throws IOException, ObjectNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Save a node with the given key
|
||||||
*
|
*
|
||||||
*
|
* @param transaction
|
||||||
* @param transaction ...
|
* @param key
|
||||||
* @param key ...
|
* @param node
|
||||||
* @param node ...
|
* @throws IOException
|
||||||
*
|
|
||||||
* @throws IOException ...
|
|
||||||
*/
|
*/
|
||||||
public void saveNode(ITransaction transaction, String key, INode node)
|
public void saveNode(ITransaction transaction, String key, INode node)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Delete the node specified by the given key.
|
||||||
*
|
*
|
||||||
* @param transaction ...
|
* @param transaction ...
|
||||||
* @param key ...
|
* @param key ...
|
||||||
*
|
|
||||||
* @throws IOException ...
|
* @throws IOException ...
|
||||||
*/
|
*/
|
||||||
public void deleteNode(ITransaction transaction, String key)
|
public void deleteNode(ITransaction transaction, String key)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
// transaction-related
|
/**
|
||||||
|
* Begin a new transaction.
|
||||||
|
*
|
||||||
|
* @return the transaction
|
||||||
|
*/
|
||||||
public ITransaction beginTransaction();
|
public ITransaction beginTransaction();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Commit a transaction, making all changes persistent
|
||||||
*
|
*
|
||||||
*
|
* @param transaction
|
||||||
* @param transaction ...
|
* @throws DatabaseException
|
||||||
*
|
|
||||||
* @throws DatabaseException ...
|
|
||||||
*/
|
*/
|
||||||
public void commitTransaction(ITransaction transaction)
|
public void commitTransaction(ITransaction transaction)
|
||||||
throws DatabaseException;
|
throws DatabaseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Abort a transaction, rolling back all changes.
|
||||||
*
|
*
|
||||||
*
|
* @param transaction
|
||||||
* @param transaction ...
|
* @throws DatabaseException
|
||||||
*
|
|
||||||
* @throws DatabaseException ...
|
|
||||||
*/
|
*/
|
||||||
public void abortTransaction(ITransaction transaction)
|
public void abortTransaction(ITransaction transaction)
|
||||||
throws DatabaseException;
|
throws DatabaseException;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import helma.objectmodel.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.io.File;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -39,8 +40,6 @@ public final class NodeManager {
|
||||||
protected Application app;
|
protected Application app;
|
||||||
private ObjectCache cache;
|
private ObjectCache cache;
|
||||||
protected IDatabase db;
|
protected IDatabase db;
|
||||||
protected IDGenerator idgen;
|
|
||||||
private long idBaseValue = 1L;
|
|
||||||
private boolean logSql;
|
private boolean logSql;
|
||||||
private Log sqlLog = null;
|
private Log sqlLog = null;
|
||||||
protected boolean logReplication;
|
protected boolean logReplication;
|
||||||
|
@ -62,7 +61,7 @@ public final class NodeManager {
|
||||||
* application properties. An embedded database will be
|
* application properties. An embedded database will be
|
||||||
* created in dbHome if one doesn't already exist.
|
* created in dbHome if one doesn't already exist.
|
||||||
*/
|
*/
|
||||||
public void init(String dbHome, Properties props)
|
public void init(File dbHome, Properties props)
|
||||||
throws DatabaseException, ClassNotFoundException,
|
throws DatabaseException, ClassNotFoundException,
|
||||||
IllegalAccessException, InstantiationException {
|
IllegalAccessException, InstantiationException {
|
||||||
String cacheImpl = props.getProperty("cacheimpl", "helma.util.CacheMap");
|
String cacheImpl = props.getProperty("cacheimpl", "helma.util.CacheMap");
|
||||||
|
@ -85,19 +84,8 @@ public final class NodeManager {
|
||||||
addNodeChangeListener(replicator);
|
addNodeChangeListener(replicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the initial id generator value
|
db = new XmlDatabase();
|
||||||
String idb = props.getProperty("idBaseValue");
|
db.init(dbHome, app);
|
||||||
|
|
||||||
if (idb != null) {
|
|
||||||
try {
|
|
||||||
idBaseValue = Long.parseLong(idb);
|
|
||||||
idBaseValue = Math.max(1L, idBaseValue); // 0 and 1 are reserved for root nodes
|
|
||||||
} catch (NumberFormatException ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db = new XmlDatabase(dbHome, this);
|
|
||||||
initDb();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,59 +102,6 @@ public final class NodeManager {
|
||||||
* Method used to create the root node and id-generator, if they don't exist already.
|
* Method used to create the root node and id-generator, if they don't exist already.
|
||||||
*/
|
*/
|
||||||
public void initDb() throws DatabaseException {
|
public void initDb() throws DatabaseException {
|
||||||
ITransaction txn = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
txn = db.beginTransaction();
|
|
||||||
|
|
||||||
try {
|
|
||||||
idgen = db.getIDGenerator(txn);
|
|
||||||
|
|
||||||
if (idgen.getValue() < idBaseValue) {
|
|
||||||
idgen.setValue(idBaseValue);
|
|
||||||
db.saveIDGenerator(txn, idgen);
|
|
||||||
}
|
|
||||||
} catch (ObjectNotFoundException notfound) {
|
|
||||||
// will start with idBaseValue+1
|
|
||||||
idgen = new IDGenerator(idBaseValue);
|
|
||||||
db.saveIDGenerator(txn, idgen);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we need to set the id generator to a base value
|
|
||||||
Node node = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
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.saveNode(txn, node.getID(), node);
|
|
||||||
registerNode(node); // register node with nodemanager cache
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
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.saveNode(txn, node.getID(), node);
|
|
||||||
registerNode(node); // register node with nodemanager cache
|
|
||||||
}
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} catch (Exception x) {
|
|
||||||
System.err.println(x);
|
|
||||||
x.printStackTrace();
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.abortTransaction(txn);
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
|
|
||||||
throw (new DatabaseException("Error initializing db"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -309,13 +309,6 @@ public class Transactor extends Thread {
|
||||||
dbm.setLastDataChange(now);
|
dbm.setLastDataChange(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the id-generator for the embedded db, if necessary
|
|
||||||
if (nmgr.idgen.dirty) {
|
|
||||||
nmgr.db.saveIDGenerator(txn, nmgr.idgen);
|
|
||||||
nmgr.idgen.dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
|
@ -20,6 +20,7 @@ import helma.objectmodel.*;
|
||||||
import helma.objectmodel.dom.IDGenParser;
|
import helma.objectmodel.dom.IDGenParser;
|
||||||
import helma.objectmodel.dom.XmlDatabaseReader;
|
import helma.objectmodel.dom.XmlDatabaseReader;
|
||||||
import helma.objectmodel.dom.XmlWriter;
|
import helma.objectmodel.dom.XmlWriter;
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -32,27 +33,24 @@ import java.util.ArrayList;
|
||||||
*/
|
*/
|
||||||
public final class XmlDatabase implements IDatabase {
|
public final class XmlDatabase implements IDatabase {
|
||||||
|
|
||||||
private File dbHomeDir;
|
protected File dbHomeDir;
|
||||||
private NodeManager nmgr;
|
protected Application app;
|
||||||
private IDGenerator idgen;
|
protected NodeManager nmgr;
|
||||||
|
protected IDGenerator idgen;
|
||||||
|
|
||||||
// character encoding to use when writing files.
|
// character encoding to use when writing files.
|
||||||
// use standard encoding by default.
|
// use standard encoding by default.
|
||||||
private String encoding = null;
|
protected String encoding = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XmlDatabase object.
|
* Initializes the database from an application.
|
||||||
*
|
* @param app
|
||||||
* @param dbHome ...
|
* @throws DatabaseException
|
||||||
* @param nmgr ...
|
|
||||||
*
|
|
||||||
* @throws DatabaseException ...
|
|
||||||
* @throws RuntimeException ...
|
|
||||||
*/
|
*/
|
||||||
public XmlDatabase(String dbHome, NodeManager nmgr)
|
public void init(File dbHome, Application app) throws DatabaseException {
|
||||||
throws DatabaseException {
|
this.app = app;
|
||||||
this.nmgr = nmgr;
|
nmgr = app.getNodeManager();
|
||||||
dbHomeDir = new File(dbHome);
|
dbHomeDir = dbHome;
|
||||||
|
|
||||||
if (!dbHomeDir.exists() && !dbHomeDir.mkdirs()) {
|
if (!dbHomeDir.exists() && !dbHomeDir.mkdirs()) {
|
||||||
throw new DatabaseException("Can't create database directory "+dbHomeDir);
|
throw new DatabaseException("Can't create database directory "+dbHomeDir);
|
||||||
|
@ -68,7 +66,70 @@ public final class XmlDatabase implements IDatabase {
|
||||||
copyStylesheet(stylesheet);
|
copyStylesheet(stylesheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.encoding = nmgr.app.getCharset();
|
this.encoding = app.getCharset();
|
||||||
|
|
||||||
|
// get the initial id generator value
|
||||||
|
long idBaseValue;
|
||||||
|
try {
|
||||||
|
idBaseValue = Long.parseLong(app.getProperty("idBaseValue", "1"));
|
||||||
|
// 0 and 1 are reserved for root nodes
|
||||||
|
idBaseValue = Math.max(1L, idBaseValue);
|
||||||
|
} catch (NumberFormatException ignore) {
|
||||||
|
idBaseValue = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITransaction txn = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
txn = beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
idgen = getIDGenerator(txn);
|
||||||
|
|
||||||
|
if (idgen.getValue() < idBaseValue) {
|
||||||
|
idgen.setValue(idBaseValue);
|
||||||
|
}
|
||||||
|
} catch (ObjectNotFoundException notfound) {
|
||||||
|
// will start with idBaseValue+1
|
||||||
|
idgen = new IDGenerator(idBaseValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we need to set the id generator to a base value
|
||||||
|
Node node = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
node = (Node) getNode(txn, "0");
|
||||||
|
node.nmgr = nmgr.safe;
|
||||||
|
} catch (ObjectNotFoundException notfound) {
|
||||||
|
node = new Node("root", "0", "Root", nmgr.safe);
|
||||||
|
node.setDbMapping(app.getDbMapping("root"));
|
||||||
|
saveNode(txn, node.getID(), node);
|
||||||
|
// register node with nodemanager cache
|
||||||
|
nmgr.registerNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
node = (Node) getNode(txn, "1");
|
||||||
|
node.nmgr = nmgr.safe;
|
||||||
|
} catch (ObjectNotFoundException notfound) {
|
||||||
|
node = new Node("users", "1", null, nmgr.safe);
|
||||||
|
node.setDbMapping(app.getDbMapping("__userroot__"));
|
||||||
|
saveNode(txn, node.getID(), node);
|
||||||
|
// register node with nodemanager cache
|
||||||
|
nmgr.registerNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
commitTransaction(txn);
|
||||||
|
} catch (Exception x) {
|
||||||
|
x.printStackTrace();
|
||||||
|
|
||||||
|
try {
|
||||||
|
abortTransaction(txn);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
throw (new DatabaseException("Error initializing db"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,6 +184,14 @@ public final class XmlDatabase implements IDatabase {
|
||||||
* @throws DatabaseException
|
* @throws DatabaseException
|
||||||
*/
|
*/
|
||||||
public void commitTransaction(ITransaction txn) throws DatabaseException {
|
public void commitTransaction(ITransaction txn) throws DatabaseException {
|
||||||
|
if (idgen.dirty) {
|
||||||
|
try {
|
||||||
|
saveIDGenerator(txn);
|
||||||
|
idgen.dirty = false;
|
||||||
|
} catch (IOException x) {
|
||||||
|
throw new DatabaseException(x.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,15 +239,13 @@ public final class XmlDatabase implements IDatabase {
|
||||||
* Write the id-generator to file.
|
* Write the id-generator to file.
|
||||||
*
|
*
|
||||||
* @param txn
|
* @param txn
|
||||||
* @param idgen
|
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void saveIDGenerator(ITransaction txn, IDGenerator idgen)
|
public void saveIDGenerator(ITransaction txn)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
File tmp = File.createTempFile("idgen.xml.", ".tmp", dbHomeDir);
|
File tmp = File.createTempFile("idgen.xml.", ".tmp", dbHomeDir);
|
||||||
|
|
||||||
IDGenParser.saveIDGenerator(idgen, tmp);
|
IDGenParser.saveIDGenerator(idgen, tmp);
|
||||||
this.idgen = idgen;
|
|
||||||
|
|
||||||
File file = new File(dbHomeDir, "idgen.xml");
|
File file = new File(dbHomeDir, "idgen.xml");
|
||||||
if (file.exists() && !file.canWrite()) {
|
if (file.exists() && !file.canWrite()) {
|
||||||
|
@ -211,7 +278,7 @@ public final class XmlDatabase implements IDatabase {
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
nmgr.app.logError("Error reading " +f, x);
|
app.logError("Error reading " +f, x);
|
||||||
throw new IOException(x.toString());
|
throw new IOException(x.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,8 +370,8 @@ public final class XmlDatabase implements IDatabase {
|
||||||
res.tmpfile.delete();
|
res.tmpfile.delete();
|
||||||
} else {
|
} else {
|
||||||
// error - leave tmp file and print a message
|
// error - leave tmp file and print a message
|
||||||
nmgr.app.logError("*** Error committing "+res.file);
|
app.logError("*** Error committing "+res.file);
|
||||||
nmgr.app.logError("*** Committed version is in "+res.tmpfile);
|
app.logError("*** Committed version is in "+res.tmpfile);
|
||||||
}
|
}
|
||||||
} catch (SecurityException ignore) {
|
} catch (SecurityException ignore) {
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
|
|
Loading…
Add table
Reference in a new issue