diff --git a/base/src/org/compiere/util/Trx.java b/base/src/org/compiere/util/Trx.java index 52c32ed4f8..2203c4eda6 100644 --- a/base/src/org/compiere/util/Trx.java +++ b/base/src/org/compiere/util/Trx.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.UUID; import java.util.logging.Level; +import org.adempiere.exceptions.AdempiereException; import org.compiere.db.CConnection; import org.compiere.db.ServerConnection; import org.compiere.interfaces.Server; @@ -46,7 +47,8 @@ import org.compiere.interfaces.Server; * - added rollback(boolean) and commit(boolean) [20070105] * - remove unnecessary use of savepoint * - use UUID for safer transaction name generation - * @version $Id$ + * @author Teo Sarca, http://www.arhipac.ro + *
+ * Example:
+ * Trx.run(null, new {@link TrxRunnable}() {
+ * public void run(String trxName) {
+ * // do something using trxName
+ * }
+ * )};
+ *
+ *
+ * @param trxName transaction name (if null, a new transaction will be created)
+ * @param r runnable object
+ */
+ public static void run(String trxName, TrxRunnable r)
+ {
+ boolean localTrx = false;
+ if (trxName == null) {
+ trxName = Trx.createTrxName("TrxRun");
+ localTrx = true;
+ }
+ Trx trx = Trx.get(trxName, true);
+ Savepoint savepoint = null;
+ try
+ {
+ if (!localTrx)
+ savepoint = trx.setSavepoint(null);
+
+ r.run(trxName);
+
+ if (localTrx)
+ trx.commit(true);
+ }
+ catch (Throwable e)
+ {
+ // Rollback transaction
+ if (localTrx)
+ {
+ trx.rollback();
+ }
+ else if (savepoint != null)
+ {
+ try {
+ trx.rollback(savepoint);
+ }
+ catch (SQLException e2) {;}
+ }
+ trx = null;
+ // Throw exception
+ if (e instanceof RuntimeException)
+ {
+ throw (RuntimeException)e;
+ }
+ else
+ {
+ throw new AdempiereException(e);
+ }
+ }
+ finally {
+ if (localTrx && trx != null)
+ {
+ trx.close();
+ trx = null;
+ }
+ }
+ }
+
} // Trx
diff --git a/base/src/org/compiere/util/TrxRunnable.java b/base/src/org/compiere/util/TrxRunnable.java
new file mode 100644
index 0000000000..5071965f26
--- /dev/null
+++ b/base/src/org/compiere/util/TrxRunnable.java
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Product: Adempiere ERP & CRM Smart Business Solution *
+ * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms version 2 of the GNU General Public License as published *
+ * by the Free Software Foundation. This program is distributed in the hope *
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
+ *****************************************************************************/
+package org.compiere.util;
+
+/**
+ * Defines an object that can be ran into an transaction,
+ * using {@link Trx#run(TrxRunnable)} or {@link Trx#run(String, TrxRunnable)} methods.
+ *
+ * @author Teo Sarca, http://www.arhipac.ro
+ */
+public interface TrxRunnable
+{
+ public void run(String trxName);
+}
diff --git a/extend/src/test/functional/FunctionalTestSuite.java b/extend/src/test/functional/FunctionalTestSuite.java
index e0ead7114a..e4173fb4d4 100644
--- a/extend/src/test/functional/FunctionalTestSuite.java
+++ b/extend/src/test/functional/FunctionalTestSuite.java
@@ -18,6 +18,7 @@ public class FunctionalTestSuite {
suite.addTestSuite(MStorageTest.class);
suite.addTestSuite(MSysConfigTest.class);
suite.addTestSuite(QueryTest.class);
+ suite.addTestSuite(TrxTest.class);
suite.addTestSuite(MRefListTest.class);
suite.addTestSuite(MUOMTest.class);
//$JUnit-END$
diff --git a/extend/src/test/functional/TrxTest.java b/extend/src/test/functional/TrxTest.java
new file mode 100644
index 0000000000..d652f9db34
--- /dev/null
+++ b/extend/src/test/functional/TrxTest.java
@@ -0,0 +1,114 @@
+/******************************************************************************
+ * Product: Adempiere ERP & CRM Smart Business Solution *
+ * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms version 2 of the GNU General Public License as published *
+ * by the Free Software Foundation. This program is distributed in the hope *
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
+ *****************************************************************************/
+package test.functional;
+
+import org.adempiere.exceptions.AdempiereException;
+import org.compiere.model.MTest;
+import org.compiere.model.Query;
+import org.compiere.util.Trx;
+import org.compiere.util.TrxRunnable;
+
+import test.AdempiereTestCase;
+
+/**
+ * Test {@link Trx} class
+ * @author Teo Sarca, http://www.arhipac.ro
+ */
+public class TrxTest extends AdempiereTestCase {
+ private int m_id2 = -1;
+
+ /**
+ * Test {@link Trx#run(TrxRunnable)} and {@link Trx#run(String, TrxRunnable)} methods
+ */
+ public void testRunTrxRunnable() throws Exception
+ {
+ //
+ // Create test outside trx - success
+ m_id2 = -1;
+ Trx.run(new TrxRunnable() {
+ public void run(String trxName) {
+ m_id2 = createTest(trxName).get_ID();
+ }
+ });
+ assertTestExists(m_id2, true, null);
+ new MTest(getCtx(), m_id2, null).deleteEx(true);
+
+ //
+ // Create test outside trx - fail
+ m_id2 = -1;
+ try {
+ Trx.run(new TrxRunnable() {
+ public void run(String trxName) {
+ m_id2 = createTest(trxName).get_ID();
+ throw new AdempiereException("FORCE");
+ }
+ });
+ //
+ assertTrue("Should not happen because previous code is throwing exception", false);
+ }
+ catch (AdempiereException e) {
+ }
+ assertTestExists(m_id2, false, null);
+
+ //
+ // Create test1
+ String trxName = getTrxName();
+ MTest test1 = createTest(trxName);
+
+ //
+ // Fail creating test2
+ m_id2 = -1;
+ try {
+ Trx.run(trxName, new TrxRunnable() {
+ public void run(String trxName) {
+ m_id2 = createTest(trxName).get_ID();
+ throw new AdempiereException("FORCE");
+ }
+ });
+ //
+ assertTrue("Should not happen because previous code is throwing exception", false);
+ }
+ catch (AdempiereException e) {
+ }
+ assertTestExists(m_id2, false, trxName);
+ assertTestExists(test1.get_ID(), true, trxName);
+
+ //
+ // Success creating test2
+ m_id2 = -1;
+ Trx.run(trxName, new TrxRunnable() {
+ public void run(String trxName) {
+ m_id2 = createTest(trxName).get_ID();
+ }
+ });
+ assertTestExists(m_id2, true, trxName);
+ assertTestExists(test1.get_ID(), true, trxName);
+ }
+
+ private final MTest createTest(String trxName) {
+ MTest test = new MTest (getCtx(), "test-"+getClass(), 10);
+ test.set_TrxName(trxName);
+ test.saveEx();
+ return test;
+ }
+
+ private final void assertTestExists(int test_id, boolean existsTarget, String trxName)
+ {
+ String whereClause = MTest.COLUMNNAME_Test_ID+"=?";
+ boolean exists = new Query(getCtx(), MTest.Table_Name, whereClause, trxName)
+ .setParameters(new Object[]{test_id})
+ .match();
+ assertEquals("Test "+test_id+" [trxName="+trxName+"] - existance issue", existsTarget, exists);
+ }
+}