Move XmlDatabase to helma.objectmodel.dom package.

Move the IDGenerator into XmlIDGenerator in the same package.
Make helma.objectmodel.db.IDGenerator an interface that can be
used to plug id generators into NodeManager.
This commit is contained in:
hns 2005-03-18 03:13:12 +00:00
parent c509e3a030
commit abaa492d2a
5 changed files with 196 additions and 85 deletions

View file

@ -16,69 +16,33 @@
package helma.objectmodel.db; package helma.objectmodel.db;
import java.io.Serializable; import helma.framework.core.Application;
/** /**
* An object that generates IDs (Strings) that are unique across the whole system. * An interface for objects that generate IDs (Strings) that are
* It does this keeping a simple long value which is incremented for each new ID. * unique for a specific type.
* This is the key generation for nodes stored in the internal database, but it can
* also be used for relational nodes if no other mechanism is available. (Sequences
* in Oracle are supported, while auto-IDs are not, since the HOP has to know
* the keys of new objects.)
*/ */
public final class IDGenerator implements Serializable { public interface IDGenerator {
static final long serialVersionUID = 753408631669789263L;
private long counter;
transient volatile boolean dirty;
/**
* Builds a new IDGenerator starting with 0.
*/
public IDGenerator() {
this.counter = 0L;
dirty = false;
}
/**
* Builds a new IDGenerator starting with value.
*/
public IDGenerator(long value) {
this.counter = value;
dirty = false;
}
/**
* Delivers a unique id and increases counter by 1.
*/
public synchronized String newID() {
counter += 1L;
dirty = true;
return Long.toString(counter);
}
/**
* Set the counter to a new value
*/
protected synchronized void setValue(long value) {
counter = value;
dirty = true;
}
/**
* Get the current counter value
*/
public long getValue() {
return counter;
}
/** /**
* Init the ID generator for the given application.
* *
* * @param app
* @return ...
*/ */
public String toString() { public void init(Application app);
return "helma.objectmodel.db.IDGenerator[counter=" + counter + ",dirty=" + dirty +
"]"; /**
} * Shut down the ID generator.
*/
public void shutdown();
/**
* Generate a new ID for a specific type.
*
* @param dbmap
* @return
*/
public String generateID(DbMapping dbmap);
} }

View file

@ -18,6 +18,7 @@ package helma.objectmodel.db;
import helma.framework.core.Application; import helma.framework.core.Application;
import helma.objectmodel.*; import helma.objectmodel.*;
import helma.objectmodel.dom.XmlDatabase;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@ -40,6 +41,7 @@ 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 boolean logSql; private boolean logSql;
private Log sqlLog = null; private Log sqlLog = null;
protected boolean logReplication; protected boolean logReplication;
@ -69,6 +71,13 @@ public final class NodeManager {
cache = (ObjectCache) Class.forName(cacheImpl).newInstance(); cache = (ObjectCache) Class.forName(cacheImpl).newInstance();
cache.init(app); cache.init(app);
String idgenImpl = props.getProperty("idGeneratorImpl");
if (idgenImpl != null) {
idgen = (IDGenerator) Class.forName(idgenImpl).newInstance();
idgen.init(app);
}
logSql = "true".equalsIgnoreCase(props.getProperty("logsql")); logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication")); logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
@ -115,6 +124,10 @@ public final class NodeManager {
cache.shutdown(); cache.shutdown();
cache = null; cache = null;
} }
if (idgen != null) {
idgen.shutdown();
}
} }
/** /**
@ -750,9 +763,27 @@ public final class NodeManager {
} }
/** /**
* Generate a new ID from an Oracle sequence. * Generate a new ID for a given type.
*/ */
public String generateID(DbMapping map) throws Exception { public String generateID(DbMapping map) throws Exception {
if (idgen != null) {
// use our custom IDGenerator
return idgen.generateID(map);
} else if ((map == null) || !map.isRelational() ||
"[hop]".equalsIgnoreCase(map.getIDgen())) {
// use embedded db id generator
return db.nextID();
} else if ((map.getIDgen() == null) ||
"[max]".equalsIgnoreCase(map.getIDgen())) {
// use select max as id generator
return generateMaxID(map);
} else {
// use db sequence as id generator
return generateSequenceID(map);
}
}
public String generateSequenceID(DbMapping map) throws Exception {
// Transactor tx = (Transactor) Thread.currentThread (); // Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("generateID "+map); // tx.timer.beginEvent ("generateID "+map);
Statement stmt = null; Statement stmt = null;

View file

@ -246,19 +246,7 @@ public final class WrappedNodeManager {
*/ */
public String generateID(DbMapping map) { public String generateID(DbMapping map) {
try { try {
if ((map == null) || !map.isRelational() ||
"[hop]".equalsIgnoreCase(map.getIDgen())) {
// use embedded db id generator
return nmgr.db.nextID();
} else if ((map.getIDgen() == null) ||
"[max]".equalsIgnoreCase(map.getIDgen())) {
// use select max as id generator
return nmgr.generateMaxID(map);
} else {
// use db sequence as id generator
return nmgr.generateID(map); return nmgr.generateID(map);
}
} catch (Exception x) { } catch (Exception x) {
if (nmgr.app.debug()) { if (nmgr.app.debug()) {
x.printStackTrace(); x.printStackTrace();

View file

@ -14,18 +14,17 @@
* $Date$ * $Date$
*/ */
package helma.objectmodel.db; package helma.objectmodel.dom;
import helma.objectmodel.*; import helma.objectmodel.*;
import helma.objectmodel.dom.IDGenParser; import helma.objectmodel.db.NodeManager;
import helma.objectmodel.db.Node;
import helma.objectmodel.dom.XmlIDGenerator;
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 helma.framework.core.Application;
import java.io.File; import java.io.*;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
@ -36,7 +35,7 @@ public final class XmlDatabase implements IDatabase {
protected File dbHomeDir; protected File dbHomeDir;
protected Application app; protected Application app;
protected NodeManager nmgr; protected NodeManager nmgr;
protected IDGenerator idgen; protected XmlIDGenerator 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.
@ -91,7 +90,7 @@ public final class XmlDatabase implements IDatabase {
} }
} catch (ObjectNotFoundException notfound) { } catch (ObjectNotFoundException notfound) {
// will start with idBaseValue+1 // will start with idBaseValue+1
idgen = new IDGenerator(idBaseValue); idgen = new XmlIDGenerator(idBaseValue);
} }
// check if we need to set the id generator to a base value // check if we need to set the id generator to a base value
@ -99,7 +98,6 @@ public final class XmlDatabase implements IDatabase {
try { try {
node = (Node) getNode(txn, "0"); node = (Node) getNode(txn, "0");
node.nmgr = nmgr.safe;
} catch (ObjectNotFoundException notfound) { } catch (ObjectNotFoundException notfound) {
node = new Node("root", "0", "Root", nmgr.safe); node = new Node("root", "0", "Root", nmgr.safe);
node.setDbMapping(app.getDbMapping("root")); node.setDbMapping(app.getDbMapping("root"));
@ -110,7 +108,6 @@ public final class XmlDatabase implements IDatabase {
try { try {
node = (Node) getNode(txn, "1"); node = (Node) getNode(txn, "1");
node.nmgr = nmgr.safe;
} catch (ObjectNotFoundException notfound) { } catch (ObjectNotFoundException notfound) {
node = new Node("users", "1", null, nmgr.safe); node = new Node("users", "1", null, nmgr.safe);
node.setDbMapping(app.getDbMapping("__userroot__")); node.setDbMapping(app.getDbMapping("__userroot__"));
@ -226,11 +223,11 @@ public final class XmlDatabase implements IDatabase {
* @return the id-generator for this database * @return the id-generator for this database
* @throws ObjectNotFoundException * @throws ObjectNotFoundException
*/ */
public IDGenerator getIDGenerator(ITransaction txn) public XmlIDGenerator getIDGenerator(ITransaction txn)
throws ObjectNotFoundException { throws ObjectNotFoundException {
File file = new File(dbHomeDir, "idgen.xml"); File file = new File(dbHomeDir, "idgen.xml");
this.idgen = IDGenParser.getIDGenerator(file); this.idgen = XmlIDGenerator.getIDGenerator(file);
return idgen; return idgen;
} }
@ -245,7 +242,7 @@ public final class XmlDatabase implements IDatabase {
throws IOException { throws IOException {
File tmp = File.createTempFile("idgen.xml.", ".tmp", dbHomeDir); File tmp = File.createTempFile("idgen.xml.", ".tmp", dbHomeDir);
IDGenParser.saveIDGenerator(idgen, tmp); XmlIDGenerator.saveIDGenerator(idgen, tmp);
File file = new File(dbHomeDir, "idgen.xml"); File file = new File(dbHomeDir, "idgen.xml");
if (file.exists() && !file.canWrite()) { if (file.exists() && !file.canWrite()) {
@ -444,5 +441,10 @@ public final class XmlDatabase implements IDatabase {
} }
} }
class IDGenerator {
}
} }

View file

@ -0,0 +1,126 @@
/*
* Helma License Notice
*
* The contents of this file are subject to the Helma License
* Version 2.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://adele.helma.org/download/helma/license.txt
*
* Copyright 1998-2003 Helma Software. All Rights Reserved.
*
* $RCSfile$
* $Author$
* $Revision$
* $Date$
*/
package helma.objectmodel.dom;
import helma.objectmodel.ObjectNotFoundException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.*;
import java.util.Date;
/**
*
*/
public class XmlIDGenerator {
private long counter;
transient volatile boolean dirty;
/**
* Builds a new IDGenerator starting with 0.
*/
public XmlIDGenerator() {
this.counter = 0L;
dirty = false;
}
/**
* Builds a new IDGenerator starting with value.
*/
public XmlIDGenerator(long value) {
this.counter = value;
dirty = false;
}
/**
* Delivers a unique id and increases counter by 1.
*/
public synchronized String newID() {
counter += 1L;
dirty = true;
return Long.toString(counter);
}
/**
* Set the counter to a new value
*/
protected synchronized void setValue(long value) {
counter = value;
dirty = true;
}
/**
* Get the current counter value
*/
public long getValue() {
return counter;
}
/**
* Returns a string representation of this IDGenerator
*/
public String toString() {
return "IDGenerator[counter=" + counter + ",dirty=" + dirty + "]";
}
/**
* Read an IDGenerator from file
*
* @param file
* @return
* @throws ObjectNotFoundException
*/
public static XmlIDGenerator 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 XmlIDGenerator(Long.parseLong(XmlUtil.getTextContent(tmp)));
} catch (Exception e) {
throw new ObjectNotFoundException(e.toString());
}
}
/**
* Save an id generator to a file.
*
* @param idgen
* @param file
* @throws IOException
*/
public static void saveIDGenerator(XmlIDGenerator idgen, File file)
throws IOException {
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file));
out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
out.write("<!-- printed by helma object publisher -->\n");
out.write("<!-- created " + (new Date()).toString() + " -->\n");
out.write("<xmlroot>\n");
out.write(" <counter>" + idgen.getValue() + "</counter>\n");
out.write("</xmlroot>\n");
out.close();
}
}