mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
99771: Merged 5.0.N (5.0.2) to HEAD-BUG-FIX (5.1/Cloud) 99702: Merged V4.2-BUG-FIX (4.2.5) to 5.0.N (5.0.2) 99655: Reverse Merge V4.2-BUG-FIX (4.2.5) << Caused build failures >> 99553: MNT-12628: Following on from MNT-12501 - Rollback of synchronous transactions is not behaving consistently - Added a static variable holding the RollbackOnly state to RetryingTransactionHelper. Currently used by RetryingTransactionInterceptor. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@100498 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -208,12 +208,6 @@ public class RetryingTransactionHelper
|
|||||||
*/
|
*/
|
||||||
private List<Class<?>> extraExceptions;
|
private List<Class<?>> extraExceptions;
|
||||||
|
|
||||||
/**
|
|
||||||
* A local variable holding the Rollback-only transaction flag which can be set by {@link #setRollbackOnly()}
|
|
||||||
* and is flushed by the
|
|
||||||
*/
|
|
||||||
private static ThreadLocal<Boolean> rollbackOnly = new ThreadLocal<Boolean>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback interface
|
* Callback interface
|
||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
@@ -464,11 +458,7 @@ public class RetryingTransactionHelper
|
|||||||
// Only commit if we 'own' the transaction.
|
// Only commit if we 'own' the transaction.
|
||||||
if (txn != null)
|
if (txn != null)
|
||||||
{
|
{
|
||||||
// Check if force rollback is on
|
if (txn.getStatus() == Status.STATUS_MARKED_ROLLBACK)
|
||||||
boolean mustRollBack = isRollbackOnly();
|
|
||||||
// This method owns the transaction; make sure we don't leak the state
|
|
||||||
rollbackOnly.set(null);
|
|
||||||
if (txn.getStatus() == Status.STATUS_MARKED_ROLLBACK || mustRollBack)
|
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@@ -521,10 +511,6 @@ public class RetryingTransactionHelper
|
|||||||
" Exception follows:",
|
" Exception follows:",
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we don't leak the state
|
|
||||||
rollbackOnly.set(null);
|
|
||||||
|
|
||||||
// Rollback if we can.
|
// Rollback if we can.
|
||||||
if (txn != null)
|
if (txn != null)
|
||||||
{
|
{
|
||||||
@@ -684,29 +670,6 @@ public class RetryingTransactionHelper
|
|||||||
return retryCause;
|
return retryCause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Returns <tt>true</tt> if the current thread transaction was marked as RollbackOnly
|
|
||||||
*/
|
|
||||||
public static boolean isRollbackOnly()
|
|
||||||
{
|
|
||||||
if (rollbackOnly.get() == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return rollbackOnly.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to set the RollbackOnly state of the transaction in the current thread
|
|
||||||
*/
|
|
||||||
public static void setRollbackOnly()
|
|
||||||
{
|
|
||||||
rollbackOnly.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method to get the active transaction. The transaction status can be queried and
|
* Utility method to get the active transaction. The transaction status can be queried and
|
||||||
* marked for rollback.
|
* marked for rollback.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -80,13 +80,11 @@ public class RetryingTransactionInterceptor extends TransactionAspectSupport imp
|
|||||||
}
|
}
|
||||||
catch (RuntimeException e)
|
catch (RuntimeException e)
|
||||||
{
|
{
|
||||||
RetryingTransactionHelper.setRollbackOnly();
|
|
||||||
completeTransactionAfterThrowing(txInfo, e);
|
completeTransactionAfterThrowing(txInfo, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
RetryingTransactionHelper.setRollbackOnly();
|
|
||||||
// Wrap non-runtime exceptions so that they can be preserved
|
// Wrap non-runtime exceptions so that they can be preserved
|
||||||
completeTransactionAfterThrowing(txInfo, e);
|
completeTransactionAfterThrowing(txInfo, e);
|
||||||
throw new WrapperException(e);
|
throw new WrapperException(e);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -703,61 +703,6 @@ public class NodeServiceTest
|
|||||||
assertEquals("Expected exact number of reference assocs", 1, childAssocRefs.size());
|
assertEquals("Expected exact number of reference assocs", 1, childAssocRefs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for MNT-12501
|
|
||||||
*/
|
|
||||||
@Test public void testRollbackTransaction()
|
|
||||||
{
|
|
||||||
final NodeRef workspaceRootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
|
||||||
final String name = GUID.generate();
|
|
||||||
final NodeRef[] nodes = new NodeRef[2];
|
|
||||||
// Now create 2 nodes with the same name and swallow the exception inside
|
|
||||||
RetryingTransactionCallback<Void> newNodeCallback = new RetryingTransactionCallback<Void>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public Void execute() throws Throwable
|
|
||||||
{
|
|
||||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>(3);
|
|
||||||
props.put(ContentModel.PROP_NAME, name);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
NodeRef node1 = nodeService.createNode(
|
|
||||||
workspaceRootNodeRef,
|
|
||||||
ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName(NAMESPACE, "duplicate"),
|
|
||||||
ContentModel.TYPE_FOLDER,
|
|
||||||
props).getChildRef();
|
|
||||||
nodes[0] = node1;
|
|
||||||
NodeRef node2 = nodeService.createNode(
|
|
||||||
workspaceRootNodeRef,
|
|
||||||
ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName(NAMESPACE, "duplicate"),
|
|
||||||
ContentModel.TYPE_FOLDER,
|
|
||||||
props).getChildRef();
|
|
||||||
nodes[1] = node2;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// swallow the exception
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
txnService.getRetryingTransactionHelper().doInTransaction(newNodeCallback);
|
|
||||||
// The exception is swallowed inside the callback
|
|
||||||
//fail("Duplicate child node name not detected.");
|
|
||||||
}
|
|
||||||
catch (DuplicateChildNodeNameException e)
|
|
||||||
{
|
|
||||||
// The exception is swallowed inside the callback
|
|
||||||
}
|
|
||||||
assertNotNull("The first node was not created.", nodes[0]);
|
|
||||||
assertFalse("The node creation should be rolled back.", nodeService.exists(nodes[0]));
|
|
||||||
assertNull("The duplicate node should not be created.", nodes[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private NodeRef setupTestGetChildren(final NodeRef workspaceRootNodeRef, final int numberOfReferences)
|
private NodeRef setupTestGetChildren(final NodeRef workspaceRootNodeRef, final int numberOfReferences)
|
||||||
{
|
{
|
||||||
RetryingTransactionCallback<NodeRef> setupCallback = new RetryingTransactionCallback<NodeRef>()
|
RetryingTransactionCallback<NodeRef> setupCallback = new RetryingTransactionCallback<NodeRef>()
|
||||||
|
Reference in New Issue
Block a user