FR [ 2080217 ] Implement TrxRunnable

This commit is contained in:
teo_sarca 2008-08-28 08:42:36 +00:00
parent aabad61689
commit b27cf2b2e5
4 changed files with 219 additions and 1 deletions

View File

@ -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
* <li>FR [ 2080217 ] Implement TrxRunnable
*/
public class Trx implements VetoableChangeListener
{
@ -676,4 +678,80 @@ public class Trx implements VetoableChangeListener
return trxs;
}
/**
* @see #run(String, TrxRunnable)
*/
public static void run(TrxRunnable r)
{
run(null, r);
}
/**
* Execute runnable object using provided transaction.
* If execution fails, database operations will be rolled back.
* <p>
* Example: <pre>
* Trx.run(null, new {@link TrxRunnable}() {
* public void run(String trxName) {
* // do something using trxName
* }
* )};
* </pre>
*
* @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

View File

@ -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);
}

View File

@ -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$

View File

@ -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);
}
}