This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch version3
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/version3 by this push:
new 1bd35d1 version 3 record transaction test
1bd35d1 is described below
commit 1bd35d1944e3a233211de5030fe8b10029ca7d39
Author: Rainer Döbele <[email protected]>
AuthorDate: Wed Jan 19 14:29:36 2022 +0100
version 3 record transaction test
---
.../org/apache/empire/samples/db/SampleApp.java | 119 ++++++++++++++++++++
.../main/java/org/apache/empire/db/DBContext.java | 22 ++++
.../main/java/org/apache/empire/db/DBRecord.java | 122 +++++++++++++++++++++
.../main/java/org/apache/empire/db/DBRecordV3.java | 72 ++++++++++++
.../org/apache/empire/db/DBRollbackHandler.java | 12 ++
.../apache/empire/db/context/DBContextBase.java | 108 ++++++++++++++++++
.../apache/empire/db/context/DBContextStatic.java | 33 ++++++
7 files changed, 488 insertions(+)
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
index 34769f3..31ede21 100644
---
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
@@ -26,10 +26,13 @@ import org.apache.empire.commons.StringUtils;
import org.apache.empire.data.bean.BeanResult;
import org.apache.empire.db.DBColumnExpr;
import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
import org.apache.empire.db.DBDatabaseDriver;
import org.apache.empire.db.DBReader;
import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordV3;
import org.apache.empire.db.DBSQLScript;
+import org.apache.empire.db.context.DBContextStatic;
import org.apache.empire.db.derby.DBDatabaseDriverDerby;
import org.apache.empire.db.h2.DBDatabaseDriverH2;
import org.apache.empire.db.hsql.DBDatabaseDriverHSql;
@@ -81,6 +84,8 @@ public class SampleApp
// STEP 2: Choose a driver
System.out.println("*** Step 2: getDatabaseProvider()
***");
DBDatabaseDriver driver =
getDatabaseDriver(config.getDatabaseProvider(), conn);
+
+ DBContext context = new DBContextStatic(driver, conn);
// STEP 3: Open Database (and create if not existing)
System.out.println("*** Step 3: openDatabase() ***");
@@ -122,6 +127,13 @@ public class SampleApp
int idPers2 = insertEmployee(conn, "Fred", "Bloggs",
Gender.M, idDevDep);
int idPers3 = insertEmployee(conn, "Emma", "White",
Gender.F, idSalDep);
+ // commit
+ db.commit(conn);
+
+ int idEmp = testTransactionCreate(context, idDevDep);
+ testTransactionUpdate(context, idEmp);
+ testTransactionDelete(context, idEmp);
+
// STEP 7: Update Records (by setting the phone Number)
System.out.println("*** Step 7: updateEmployee() ***");
updateEmployee(conn, idPers1, "+49-7531-457160");
@@ -326,6 +338,113 @@ public class SampleApp
}
/**
+ * @param context
+ * @param idDep
+ */
+ private static int testTransactionCreate(DBContext context, int idDep)
+ {
+ SampleDB.Employees T = db.EMPLOYEES;
+ DBRecordV3 rec = new DBRecordV3(context, T);
+
+ rec.create();
+ rec.setValue(T.FIRSTNAME, "Foo");
+ rec.setValue(T.LASTNAME, "Manchoo");
+ rec.setValue(T.GENDER, Gender.M);
+ rec.setValue(T.DEPARTMENT_ID, idDep);
+ rec.update();
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ rec.setValue(T.FIRSTNAME, "Foo 2");
+ rec.setValue(T.LASTNAME, "Manchu");
+ rec.setValue(T.PHONE_NUMBER, "0815/4711");
+ rec.update();
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ context.rollback();
+
+ rec.setValue(T.FIRSTNAME, "Dr. Foo");
+ rec.update();
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ rec.delete();
+
+ context.rollback();
+
+ // insert final
+ rec.update();
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ log.info("testTransactionCreate performed OK");
+ context.commit();
+
+ return rec.getInt(T.EMPLOYEE_ID);
+ }
+ /**
+ * @param context
+ * @param idDep
+ */
+ private static void testTransactionUpdate(DBContext context, int idEmp)
+ {
+ SampleDB.Employees T = db.EMPLOYEES;
+ DBRecordV3 rec = new DBRecordV3(context, T);
+
+ rec.read(idEmp);
+ rec.setValue(T.PHONE_NUMBER, null);
+ rec.setValue(T.SALARY, "100.000");
+ rec.update();
+
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ context.rollback();
+
+ rec.setValue(T.PHONE_NUMBER, "07531-45716-0");
+ rec.update();
+
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+
+ context.rollback();
+
+ rec.update();
+
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+ log.info("testTransactionUpdate performed OK");
+ context.commit();
+
+ }
+ /**
+ * @param context
+ * @param idDep
+ */
+ private static void testTransactionDelete(DBContext context, int idEmp)
+ {
+ SampleDB.Employees T = db.EMPLOYEES;
+ DBRecordV3 rec = new DBRecordV3(context, T);
+
+ rec.read(idEmp);
+ /*
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+ rec.setValue(T.SALARY, "100.001");
+ rec.update();
+ log.info("Timestamp {}", rec.getString(T.UPDATE_TIMESTAMP));
+ */
+ rec.delete();
+
+ context.rollback();
+
+ /*
+ DBCommand cmd = db.createCommand();
+ cmd.select(T.UPDATE_TIMESTAMP);
+ cmd.where (T.EMPLOYEE_ID.is(idEmp));
+ log.info("Timestamp {}", db.querySingleString(cmd,
context.getConnection()));
+ */
+
+ rec.update();
+
+ log.info("Transaction performed OK");
+
+ }
+
+ /**
* <PRE>
* Performs an SQL-Query and prints the result to System.out
*
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBContext.java
b/empire-db/src/main/java/org/apache/empire/db/DBContext.java
new file mode 100644
index 0000000..51e7017
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/DBContext.java
@@ -0,0 +1,22 @@
+/*
+ * ESTEAM Software GmbH, 19.01.2022
+ */
+package org.apache.empire.db;
+
+import java.sql.Connection;
+
+public interface DBContext
+{
+ DBDatabaseDriver getDriver();
+
+ Connection getConnection();
+
+ void commit();
+
+ void rollback();
+
+ void removeRollbackHandler(DBObject object);
+
+ void addRollbackHandler(DBRollbackHandler handler);
+
+}
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
index d3ac89b..091db47 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
@@ -54,6 +54,128 @@ import org.w3c.dom.Element;
public class DBRecord extends DBRecordData implements Record, Cloneable
{
private final static long serialVersionUID = 1L;
+
+ /**
+ * DBRecordRollbackHandler
+ * @author doebele
+ */
+ public static class DBRecordRollbackHandler implements DBRollbackHandler
+ {
+ // Logger
+ private static final Logger log =
LoggerFactory.getLogger(DBRecordRollbackHandler.class);
+
+ public final DBRecord record;
+
+ private final State state; /* the original state */
+ private Object[] fields;
+ private boolean[] modified;
+ private Object rowsetData;
+
+ public DBRecordRollbackHandler(DBRecord record)
+ {
+ this.record = record;
+ // check
+ if (record.state==State.Invalid)
+ throw new ObjectNotValidException(record);
+ // save state
+ this.state = record.state;
+ this.modified = copy(record.modified);
+ this.fields = copy(record.fields);
+ this.rowsetData = record.rowsetData;
+ }
+
+ @Override
+ public DBObject getObject()
+ {
+ return record;
+ }
+
+ @Override
+ public void combine(DBRollbackHandler successor)
+ {
+ if (record!=successor.getObject())
+ throw new InvalidArgumentException("successor", successor);
+ // combine now
+ DBRecordRollbackHandler s = (DBRecordRollbackHandler)successor;
+ log.info("combining rollback state for record {}/{}",
record.getRowSet().getName(), StringUtils.arrayToString(record.getKeyValues(),
"|"));
+ if (s.modified==null)
+ {
+ return; // not modified!
+ }
+ // copy
+ for (int i=0; i<fields.length; i++)
+ {
+ if (fields[i]!= s.fields[i])
+ fields[i] = s.fields[i];
+ // not modified
+ if (modified==null)
+ continue;
+ if (modified[i]==false && s.modified[i])
+ modified[i] = s.modified[i];
+ }
+ // check modified
+ if (modified==null && s.modified!=null)
+ modified = copy(s.modified);
+ /*
+ if (this.fields==s.fields)
+ {
+ // combine modified
+ if (this.modified==null)
+ this.modified =s.modified; // for delete case only!
+ else if (s.modified!=null)
+ combineModified(s.modified);
+ }
+ else
+ { // warn
+ log.warn("record fields have changed {}/{}",
record.getRowSet().getName(), StringUtils.arrayToString(record.getKeyValues(),
"|"));
+ this.fields = s.fields;
+ this.modified = s.modified;
+ }
+ */
+ }
+
+ @Override
+ public void rollback()
+ {
+ // rollback
+ record.state = this.state;
+ record.fields = this.fields;
+ record.modified = this.modified;
+ record.rowsetData = rowsetData;
+ // done
+ log.info("Rollback for record {}/{} performed",
record.getRowSet().getName(), StringUtils.arrayToString(record.getKeyValues(),
"|"));
+ }
+
+ @Override
+ public void discard()
+ {
+ /* nothing */
+ }
+
+ private boolean[] copy(boolean[] other)
+ {
+ if (other==null)
+ return null;
+ boolean[] copy = new boolean[other.length];
+ for (int i=0; i<copy.length; i++)
+ {
+ copy[i] = other[i];
+ }
+ return copy;
+ }
+
+ private Object[] copy(Object[] other)
+ {
+ if (other==null)
+ return null;
+ Object[] copy = new Object[other.length];
+ for (int i=0; i<copy.length; i++)
+ {
+ copy[i] = other[i];
+ }
+ return copy;
+ }
+ }
/* Record state enum */
public enum State
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecordV3.java
b/empire-db/src/main/java/org/apache/empire/db/DBRecordV3.java
new file mode 100644
index 0000000..ba13ca0
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordV3.java
@@ -0,0 +1,72 @@
+/*
+ * ESTEAM Software GmbH, 19.01.2022
+ */
+package org.apache.empire.db;
+
+import org.apache.empire.exceptions.ObjectNotValidException;
+
+public class DBRecordV3 extends DBRecord
+{
+
+ private static final long serialVersionUID = 1L;
+
+ private final DBContext context;
+
+ public DBRecordV3(DBContext context, DBRowSet rowset)
+ {
+ super(rowset);
+ this.context = context;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends DBContext> T getContext()
+ {
+ return ((T)context);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends DBRowSet> T getTable()
+ {
+ return (T)super.getRowSet();
+ }
+
+ public void create()
+ {
+ super.create(getRowSet());
+ // remove rollback
+ context.removeRollbackHandler(this);
+ }
+
+ public void read(Object... key)
+ {
+ super.read(getRowSet(), key, context.getConnection());
+ // remove rollback
+ context.removeRollbackHandler(this);
+ }
+
+ public void update()
+ {
+ if (!isValid())
+ throw new ObjectNotValidException(this);
+ if (!isModified())
+ return; /* Not modified. Nothing to do! */
+ // allow rollback
+ context.addRollbackHandler(createRollbackHandler());
+ // update
+ super.update(context.getConnection());
+ }
+
+ public void delete()
+ {
+ // allow rollback
+ context.addRollbackHandler(createRollbackHandler());
+ // delete
+ super.delete(context.getConnection());
+ }
+
+ protected DBRollbackHandler createRollbackHandler()
+ {
+ return new DBRecordRollbackHandler(this);
+ }
+
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/DBRollbackHandler.java
b/empire-db/src/main/java/org/apache/empire/db/DBRollbackHandler.java
new file mode 100644
index 0000000..6e79a19
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRollbackHandler.java
@@ -0,0 +1,12 @@
+/*
+ * ESTEAM Software GmbH, 19.01.2022
+ */
+package org.apache.empire.db;
+
+public interface DBRollbackHandler
+{
+ DBObject getObject();
+ void combine(DBRollbackHandler successor);
+ void rollback();
+ void discard();
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
b/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
new file mode 100644
index 0000000..5f4c6af
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
@@ -0,0 +1,108 @@
+/*
+ * ESTEAM Software GmbH, 19.01.2022
+ */
+package org.apache.empire.db.context;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBObject;
+import org.apache.empire.db.DBRollbackHandler;
+import org.apache.empire.db.exceptions.EmpireSQLException;
+import org.apache.empire.exceptions.InvalidArgumentException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class DBContextBase implements DBContext
+{
+ // Logger
+ private static final Logger log =
LoggerFactory.getLogger(DBContextBase.class);
+
+ private Map<DBObject, DBRollbackHandler> rollbackHandler;
+
+ @Override
+ public synchronized void commit()
+ {
+ try
+ { // Check argument
+ Connection conn = getConnection();
+ if (conn==null)
+ throw new InvalidArgumentException("conn", conn);
+ // Commit
+ if (conn.getAutoCommit()==false)
+ conn.commit();
+ // discard rollbacks
+ if (rollbackHandler!=null)
+ for (DBRollbackHandler handler : rollbackHandler.values())
+ handler.discard();
+ // Done
+ return;
+ } catch (SQLException sqle) {
+ // Commit failed!
+ throw new EmpireSQLException(getDriver(), sqle);
+ } finally {
+ rollbackHandler=null;
+ }
+ }
+
+ /**
+ * Discards all changes made since the previous commit/rollback
+ * and releases any database locks currently held by this
+ * Connection.
+ * <P>
+ * @param conn a valid database connection
+ */
+ @Override
+ public synchronized void rollback()
+ {
+ try
+ { // Check argument
+ Connection conn = getConnection();
+ if (conn==null)
+ throw new InvalidArgumentException("conn", conn);
+ // rollback
+ log.info("Database rollback issued!");
+ conn.rollback();
+ // rollback
+ if (rollbackHandler!=null)
+ for (DBRollbackHandler handler : rollbackHandler.values())
+ handler.rollback();
+ // Done
+ return;
+ } catch (SQLException sqle) {
+ // Commit failed!
+ throw new EmpireSQLException(getDriver(), sqle);
+ } finally {
+ rollbackHandler=null;
+ }
+ }
+
+ @Override
+ public synchronized void addRollbackHandler(DBRollbackHandler handler)
+ {
+ if (rollbackHandler==null)
+ rollbackHandler = new LinkedHashMap<DBObject, DBRollbackHandler>();
+ // check
+ DBObject object = handler.getObject();
+ if (rollbackHandler.containsKey(object))
+ rollbackHandler.get(object).combine(handler);
+ else
+ rollbackHandler.put(object, handler);
+ }
+
+ @Override
+ public synchronized void removeRollbackHandler(DBObject object)
+ {
+ if (rollbackHandler!=null && rollbackHandler.containsKey(object))
+ log.info("test");
+
+ if (object==null)
+ rollbackHandler=null; // remove all
+ else if (rollbackHandler!=null && rollbackHandler.remove(object)!=null)
+ log.info("Rollback handler for object {} was removed",
object.getClass().getSimpleName());
+ }
+
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/context/DBContextStatic.java
b/empire-db/src/main/java/org/apache/empire/db/context/DBContextStatic.java
new file mode 100644
index 0000000..2102af4
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/context/DBContextStatic.java
@@ -0,0 +1,33 @@
+/*
+ * ESTEAM Software GmbH, 19.01.2022
+ */
+package org.apache.empire.db.context;
+
+import java.sql.Connection;
+
+import org.apache.empire.db.DBDatabaseDriver;
+
+public class DBContextStatic extends DBContextBase
+{
+ private final DBDatabaseDriver driver;
+ private final Connection conn;
+
+ public DBContextStatic(DBDatabaseDriver driver, Connection conn)
+ {
+ this.driver = driver;
+ this.conn = conn;
+ }
+
+ @Override
+ public DBDatabaseDriver getDriver()
+ {
+ return driver;
+ }
+
+ @Override
+ public Connection getConnection()
+ {
+ return conn;
+ }
+
+}