mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-02 17:35:18 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4621 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
155 lines
4.7 KiB
Java
155 lines
4.7 KiB
Java
/**
|
|
*
|
|
*/
|
|
package org.alfresco.repo.transaction;
|
|
|
|
import java.util.Random;
|
|
|
|
import org.aopalliance.intercept.MethodInterceptor;
|
|
import org.aopalliance.intercept.MethodInvocation;
|
|
import org.apache.log4j.Logger;
|
|
import org.hibernate.StaleObjectStateException;
|
|
import org.hibernate.exception.LockAcquisitionException;
|
|
import org.springframework.aop.framework.ReflectiveMethodInvocation;
|
|
import org.springframework.dao.ConcurrencyFailureException;
|
|
import org.springframework.dao.DeadlockLoserDataAccessException;
|
|
import org.springframework.transaction.PlatformTransactionManager;
|
|
import org.springframework.transaction.TransactionDefinition;
|
|
import org.springframework.transaction.TransactionStatus;
|
|
|
|
/**
|
|
*
|
|
* @author britt
|
|
*/
|
|
public class RetryingTransactionAdvice implements MethodInterceptor
|
|
{
|
|
private static Logger fgLogger = Logger.getLogger(RetryingTransactionAdvice.class);
|
|
|
|
/**
|
|
* The transaction manager instance.
|
|
*/
|
|
private PlatformTransactionManager fTxnManager;
|
|
|
|
/**
|
|
* The TransactionDefinition.
|
|
*/
|
|
private TransactionDefinition fDefinition;
|
|
|
|
/**
|
|
* The maximum number of retries.
|
|
*/
|
|
private int fMaxRetries;
|
|
|
|
/**
|
|
* A Random number generator for getting retry intervals.
|
|
*/
|
|
private Random fRandom;
|
|
|
|
public RetryingTransactionAdvice()
|
|
{
|
|
fRandom = new Random(System.currentTimeMillis());
|
|
}
|
|
|
|
/**
|
|
* Setter.
|
|
*/
|
|
public void setTransactionManager(PlatformTransactionManager manager)
|
|
{
|
|
fTxnManager = manager;
|
|
}
|
|
|
|
/**
|
|
* Setter.
|
|
*/
|
|
public void setTransactionDefinition(TransactionDefinition def)
|
|
{
|
|
fDefinition = def;
|
|
}
|
|
|
|
/**
|
|
* Setter.
|
|
*/
|
|
public void setMaxRetries(int maxRetries)
|
|
{
|
|
fMaxRetries = maxRetries;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
|
*/
|
|
public Object invoke(MethodInvocation methodInvocation) throws Throwable
|
|
{
|
|
RuntimeException lastException = null;
|
|
for (int count = 0; fMaxRetries < -1 || count < fMaxRetries; count++)
|
|
{
|
|
TransactionStatus txn = null;
|
|
boolean isNewTxn = false;
|
|
try
|
|
{
|
|
txn = fTxnManager.getTransaction(fDefinition);
|
|
isNewTxn = txn.isNewTransaction();
|
|
MethodInvocation clone = ((ReflectiveMethodInvocation)methodInvocation).invocableClone();
|
|
Object result = clone.proceed();
|
|
if (isNewTxn)
|
|
{
|
|
fTxnManager.commit(txn);
|
|
}
|
|
if (fgLogger.isDebugEnabled())
|
|
{
|
|
if (count != 0)
|
|
{
|
|
fgLogger.debug("Transaction succeeded after " + count + " retries.");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
catch (RuntimeException e)
|
|
{
|
|
if (txn != null && isNewTxn && !txn.isCompleted())
|
|
{
|
|
fTxnManager.rollback(txn);
|
|
}
|
|
if (!isNewTxn)
|
|
{
|
|
throw e;
|
|
}
|
|
lastException = e;
|
|
Throwable t = e;
|
|
boolean shouldRetry = false;
|
|
while (t != null)
|
|
{
|
|
if (t instanceof ConcurrencyFailureException ||
|
|
t instanceof DeadlockLoserDataAccessException ||
|
|
t instanceof StaleObjectStateException ||
|
|
t instanceof LockAcquisitionException)
|
|
{
|
|
shouldRetry = true;
|
|
try
|
|
{
|
|
Thread.sleep(fRandom.nextInt(500 * count + 500));
|
|
}
|
|
catch (InterruptedException ie)
|
|
{
|
|
// Do nothing.
|
|
}
|
|
break;
|
|
}
|
|
// Apparently java.lang.Throwable default the cause as 'this'.
|
|
if (t == t.getCause())
|
|
{
|
|
break;
|
|
}
|
|
t = t.getCause();
|
|
}
|
|
if (shouldRetry)
|
|
{
|
|
continue;
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
fgLogger.error("Txn Failed after " + fMaxRetries + " retries:", lastException);
|
|
throw lastException;
|
|
}
|
|
}
|