mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V2.9 to HEAD
10586: Merged V2.2 to V2.9 9883: Fix for https://issues.alfresco.com/jira/browse/ETWOTWO-561 9893: Gave some more time to wait for the threads to finish (QNameDAOTest) 9955: Added trace logging of calls that possibly cause failures during session flushing 9956: Part fix ETWOTWO570: RetryingTransactionAdvice needs to use RetryingTransactionHelper 9958: Fixed ETWOTWO-570: AVM transaction interceptors fail if methods are incorrectly declared 9973: More missing transaction declarations for AttributeService 9977: Fixed unit test to rollback properly after expected txn failure 9978: Fix for ETWOTWO-440: Error : 500: Failed to execute method NodeInfoBean.sendNodeInfo 9986: LinkValidationService missing txn declaration for onBootstrap 10588: Merged V2.2 to V2.9 9898: Fixed handling of cm:name on root nodes 9900: Empty property sets are allowed 10589: Merged V2.2 to V2.9 9965: Fixed unit test to inject 'nodeService' and not 'NodeService'. 10311: getWebProjectUserRole - change log level from info to debug 10329: Fix missing and mis-spelt transaction declarations 10343: Fix for ETWOTWO-32 10346: Build Fix 10358: Fix for ETWOTWO-621 10362: Fix for ETWOTWO-518 10371: QNameDAO cache doesn't blow up if cache entry is invalid 10538: Fix for minor XSS issue identified in ETWOTWO-657 item 3 10678: Merged V2.2 to V2.9 10205: Fix for ETWOTWO-48: Cancelled import of war into a Web project and Web Project became unusable 10206: Fix for ETWOTWO-181: Deletion of checked out document git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10710 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,160 +1,75 @@
|
||||
/**
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.transaction;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A this advice wrapper around the {@link RetryingTransactionHelper}.
|
||||
*
|
||||
* @author britt
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class RetryingTransactionAdvice implements MethodInterceptor
|
||||
{
|
||||
private static Log fgLogger = LogFactory.getLog(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;
|
||||
private RetryingTransactionHelper txnHelper;
|
||||
private boolean readOnly;
|
||||
private boolean requiresNew;
|
||||
|
||||
public RetryingTransactionAdvice()
|
||||
{
|
||||
fRandom = new Random(System.currentTimeMillis());
|
||||
readOnly = false;
|
||||
requiresNew = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter.
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager manager)
|
||||
public void setTxnHelper(RetryingTransactionHelper txnHelper)
|
||||
{
|
||||
fTxnManager = manager;
|
||||
this.txnHelper = txnHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter.
|
||||
*/
|
||||
public void setTransactionDefinition(TransactionDefinition def)
|
||||
public void setReadOnly(boolean readOnly)
|
||||
{
|
||||
fDefinition = def;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter.
|
||||
*/
|
||||
public void setMaxRetries(int maxRetries)
|
||||
public void setRequiresNew(boolean requiresNew)
|
||||
{
|
||||
fMaxRetries = maxRetries;
|
||||
this.requiresNew = requiresNew;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
public Object invoke(MethodInvocation methodInvocation) throws Throwable
|
||||
public Object invoke(final MethodInvocation methodInvocation) throws Throwable
|
||||
{
|
||||
RuntimeException lastException = null;
|
||||
for (int count = 0; fMaxRetries < -1 || count < fMaxRetries; count++)
|
||||
// Just call the helper
|
||||
RetryingTransactionCallback<Object> txnCallback = new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
TransactionStatus txn = null;
|
||||
boolean isNewTxn = false;
|
||||
try
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
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;
|
||||
return methodInvocation.proceed();
|
||||
}
|
||||
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 ||
|
||||
t instanceof StaleStateException ||
|
||||
t instanceof ConstraintViolationException)
|
||||
{
|
||||
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)
|
||||
{
|
||||
fgLogger.warn("Retry #" + (count + 1));
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
fgLogger.error("Txn Failed after " + fMaxRetries + " retries:", lastException);
|
||||
throw lastException;
|
||||
};
|
||||
return txnHelper.doInTransaction(txnCallback, readOnly, requiresNew);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user