diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml
index 6a55930f53..9cbf25a7b3 100644
--- a/config/alfresco/action-services-context.xml
+++ b/config/alfresco/action-services-context.xml
@@ -25,7 +25,7 @@
-
+
diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index 62cd4bc666..5adf5c14bb 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -11,7 +11,7 @@
node
-
+
@@ -20,7 +20,7 @@
layer
-
+
@@ -171,7 +171,7 @@
1000
-
+
diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index eea9358eca..7f548934bf 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -254,7 +254,7 @@
-
+
@@ -296,7 +296,7 @@
-
+
@@ -319,7 +319,7 @@
-
+
diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index d6c1a8f5b4..0907691dae 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -33,7 +33,7 @@
-
+
14
@@ -52,7 +52,7 @@
-
+
diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml
index d6945f3750..5bcbdd568d 100644
--- a/config/alfresco/core-services-context.xml
+++ b/config/alfresco/core-services-context.xml
@@ -145,7 +145,8 @@
-
+
+
@@ -156,10 +157,10 @@
-
+
- 20
+ ${server.transaction.max-retries}
@@ -654,7 +655,7 @@
-
+
@@ -776,7 +777,7 @@
-
+
diff --git a/config/alfresco/domain/transaction.properties b/config/alfresco/domain/transaction.properties
index f0d6d6d583..f5c65ba4a4 100644
--- a/config/alfresco/domain/transaction.properties
+++ b/config/alfresco/domain/transaction.properties
@@ -7,3 +7,5 @@ server.transaction.mode.readOnly=PROPAGATION_REQUIRED, readOnly
#server.transaction.allow-writes=false
server.transaction.mode.default=PROPAGATION_REQUIRED
server.transaction.allow-writes=true
+
+server.transaction.max-retries=20
diff --git a/config/alfresco/import-export-context.xml b/config/alfresco/import-export-context.xml
index ca88c658ff..e564233750 100644
--- a/config/alfresco/import-export-context.xml
+++ b/config/alfresco/import-export-context.xml
@@ -181,7 +181,7 @@
-
+
@@ -203,7 +203,7 @@
-
+
diff --git a/config/alfresco/index-recovery-context.xml b/config/alfresco/index-recovery-context.xml
index ebe7b15b41..806af263d9 100644
--- a/config/alfresco/index-recovery-context.xml
+++ b/config/alfresco/index-recovery-context.xml
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/config/alfresco/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml
index 490f856887..862e3d3789 100644
--- a/config/alfresco/network-protocol-context.xml
+++ b/config/alfresco/network-protocol-context.xml
@@ -38,7 +38,7 @@
-
+
@@ -53,7 +53,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml
index 7d2ac5eb62..542e20757f 100644
--- a/config/alfresco/node-services-context.xml
+++ b/config/alfresco/node-services-context.xml
@@ -63,7 +63,7 @@
-
+
diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml
index 16f5a50861..b161702864 100644
--- a/config/alfresco/patch/patch-services-context.xml
+++ b/config/alfresco/patch/patch-services-context.xml
@@ -51,7 +51,7 @@
-
+
diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml
index acbc9d47eb..559ce117b8 100644
--- a/config/alfresco/workflow-context.xml
+++ b/config/alfresco/workflow-context.xml
@@ -8,7 +8,7 @@
-
+
@@ -36,7 +36,7 @@
-
+
diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java
index b27bb82865..5c742b5f26 100644
--- a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java
+++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java
@@ -38,7 +38,7 @@ import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.transaction.TransactionComponent;
+import org.alfresco.repo.transaction.TransactionServiceImpl;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -72,7 +72,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
private AuthenticationComponent authenticationComponent;
/** provides transactions to atomically index each missed transaction */
- protected TransactionComponent transactionService;
+ protected TransactionServiceImpl transactionService;
/** the component to index the node hierarchy */
protected Indexer indexer;
/** the FTS indexer that we will prompt to pick up on any un-indexed text */
@@ -136,9 +136,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery
*
* @param transactionComponent provide transactions to index each missed transaction
*/
- public void setTransactionComponent(TransactionComponent transactionComponent)
+ public void setTransactionService(TransactionServiceImpl transactionService)
{
- this.transactionService = transactionComponent;
+ this.transactionService = transactionService;
}
/**
diff --git a/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java
index 8161acab05..30a93e2cd2 100644
--- a/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java
+++ b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java
@@ -32,7 +32,7 @@ import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
-import org.alfresco.repo.transaction.TransactionComponent;
+import org.alfresco.repo.transaction.TransactionServiceImpl;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.ServiceRegistry;
@@ -89,7 +89,7 @@ public class IndexRemoteTransactionTrackerTest extends TestCase
indexTracker.setNodeDaoService(nodeDaoService);
indexTracker.setNodeService(nodeService);
indexTracker.setSearcher(searchService);
- indexTracker.setTransactionComponent((TransactionComponent)transactionService);
+ indexTracker.setTransactionService((TransactionServiceImpl)transactionService);
// authenticate
authenticationComponent.setSystemUserAsCurrentUser();
diff --git a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java
index f09bb697d4..11ecb1641e 100644
--- a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java
+++ b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java
@@ -35,7 +35,7 @@ import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.impl.lucene.AbstractLuceneIndexerImpl;
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
-import org.alfresco.repo.transaction.TransactionComponent;
+import org.alfresco.repo.transaction.TransactionServiceImpl;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentData;
@@ -91,7 +91,7 @@ public class MissingContentReindexComponentTest extends TestCase
reindexer.setNodeDaoService(nodeDaoService);
reindexer.setNodeService(nodeService);
reindexer.setSearcher(searchService);
- reindexer.setTransactionComponent((TransactionComponent)transactionService);
+ reindexer.setTransactionService((TransactionServiceImpl)transactionService);
// authenticate
authenticationComponent.setSystemUserAsCurrentUser();
diff --git a/source/java/org/alfresco/repo/transaction/DummyTransactionService.java b/source/java/org/alfresco/repo/transaction/DummyTransactionService.java
index 01f310c64c..c05631dcaf 100644
--- a/source/java/org/alfresco/repo/transaction/DummyTransactionService.java
+++ b/source/java/org/alfresco/repo/transaction/DummyTransactionService.java
@@ -76,4 +76,13 @@ public class DummyTransactionService implements TransactionService
{
return txn;
}
+
+ public RetryingTransactionHelper getRetryingTransactionHelper()
+ {
+ RetryingTransactionHelper helper = new RetryingTransactionHelper();
+ helper.setMaxRetries(20);
+ helper.setTransactionService(this);
+ helper.setReadOnly(false);
+ return helper;
+ }
}
diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
index f8c2df7ec1..d038fce041 100644
--- a/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
+++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionHelper.java
@@ -32,6 +32,7 @@ import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.error.ExceptionStackUtil;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.transaction.TransactionService;
import org.apache.log4j.Logger;
import org.hibernate.StaleObjectStateException;
@@ -48,6 +49,7 @@ import org.springframework.dao.DeadlockLoserDataAccessException;
*/
public class RetryingTransactionHelper
{
+ private static final String MSG_READ_ONLY = "permissions.err_read_only";
private static Logger fgLogger = Logger.getLogger(RetryingTransactionHelper.class);
/**
@@ -74,6 +76,11 @@ public class RetryingTransactionHelper
*/
private int fMaxRetries;
+ /**
+ * Whether the the transactions may only be reads
+ */
+ private boolean readOnly;
+
/**
* Random number generator for retry delays.
*/
@@ -119,6 +126,14 @@ public class RetryingTransactionHelper
fMaxRetries = maxRetries;
}
+ /**
+ * Set whether this helper only supports read transactions.
+ */
+ public void setReadOnly(boolean readOnly)
+ {
+ this.readOnly = readOnly;
+ }
+
/**
* Execute a callback in a transaction until it succeeds, fails
* because of an error not the result of an optimistic locking failure,
@@ -172,6 +187,10 @@ public class RetryingTransactionHelper
*/
public R doInTransaction(RetryingTransactionCallback cb, boolean readOnly, boolean newTransaction)
{
+ if (this.readOnly && !readOnly)
+ {
+ throw new AccessDeniedException(MSG_READ_ONLY);
+ }
// Track the last exception caught, so that we
// can throw it if we run out of retries.
RuntimeException lastException = null;
@@ -208,7 +227,9 @@ public class RetryingTransactionHelper
{
if (count != 0)
{
- fgLogger.debug("Transaction succeeded after " + count + " retries");
+ fgLogger.debug(
+ "Transaction succeeded after " + count +
+ " retries on thread " + Thread.currentThread().getName());
}
}
return result;
diff --git a/source/java/org/alfresco/repo/transaction/TransactionComponent.java b/source/java/org/alfresco/repo/transaction/TransactionServiceImpl.java
similarity index 82%
rename from source/java/org/alfresco/repo/transaction/TransactionComponent.java
rename to source/java/org/alfresco/repo/transaction/TransactionServiceImpl.java
index 70a1277dca..f318f68ab6 100644
--- a/source/java/org/alfresco/repo/transaction/TransactionComponent.java
+++ b/source/java/org/alfresco/repo/transaction/TransactionServiceImpl.java
@@ -36,10 +36,11 @@ import org.springframework.transaction.TransactionDefinition;
*
* @author David Caruana
*/
-public class TransactionComponent implements TransactionService
+public class TransactionServiceImpl implements TransactionService
{
private PlatformTransactionManager transactionManager;
private boolean readOnly = false;
+ private int maxRetries = 20;
/**
* Set the transaction manager to use
@@ -65,6 +66,17 @@ public class TransactionComponent implements TransactionService
{
return readOnly;
}
+
+ /**
+ * Set the maximum number of retries that will be done by the
+ * {@link RetryingTransactionHelper transaction helper}.
+ *
+ * @param maxRetries the maximum transaction retries
+ */
+ public void setMaxRetries(int maxRetries)
+ {
+ this.maxRetries = maxRetries;
+ }
/**
* @see org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRED
@@ -121,4 +133,16 @@ public class TransactionComponent implements TransactionService
TransactionDefinition.TIMEOUT_DEFAULT);
return txn;
}
+
+ /**
+ * Creates a new helper instance. It can be reused.
+ */
+ public RetryingTransactionHelper getRetryingTransactionHelper()
+ {
+ RetryingTransactionHelper helper = new RetryingTransactionHelper();
+ helper.setMaxRetries(maxRetries);
+ helper.setTransactionService(this);
+ helper.setReadOnly(readOnly);
+ return helper;
+ }
}
diff --git a/source/java/org/alfresco/repo/transaction/TransactionComponentTest.java b/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java
similarity index 65%
rename from source/java/org/alfresco/repo/transaction/TransactionComponentTest.java
rename to source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java
index 8235ff9f94..b859d64e75 100644
--- a/source/java/org/alfresco/repo/transaction/TransactionComponentTest.java
+++ b/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java
@@ -30,6 +30,8 @@ import javax.transaction.UserTransaction;
import junit.framework.TestCase;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.ApplicationContextHelper;
@@ -38,24 +40,24 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.transaction.PlatformTransactionManager;
/**
- * @see org.alfresco.repo.transaction.TransactionComponent
+ * @see org.alfresco.repo.transaction.TransactionServiceImpl
*
* @author Derek Hulley
*/
-public class TransactionComponentTest extends TestCase
+public class TransactionServiceImplTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private PlatformTransactionManager transactionManager;
- private TransactionComponent transactionComponent;
+ private TransactionServiceImpl transactionService;
private NodeService nodeService;
public void setUp() throws Exception
{
transactionManager = (PlatformTransactionManager) ctx.getBean("transactionManager");
- transactionComponent = new TransactionComponent();
- transactionComponent.setTransactionManager(transactionManager);
- transactionComponent.setAllowWrite(true);
+ transactionService = new TransactionServiceImpl();
+ transactionService.setTransactionManager(transactionManager);
+ transactionService.setAllowWrite(true);
nodeService = (NodeService) ctx.getBean("dbNodeService");
}
@@ -63,12 +65,12 @@ public class TransactionComponentTest extends TestCase
public void testPropagatingTxn() throws Exception
{
// start a transaction
- UserTransaction txnOuter = transactionComponent.getUserTransaction();
+ UserTransaction txnOuter = transactionService.getUserTransaction();
txnOuter.begin();
String txnIdOuter = AlfrescoTransactionSupport.getTransactionId();
// start a propagating txn
- UserTransaction txnInner = transactionComponent.getUserTransaction();
+ UserTransaction txnInner = transactionService.getUserTransaction();
txnInner.begin();
String txnIdInner = AlfrescoTransactionSupport.getTransactionId();
@@ -97,12 +99,12 @@ public class TransactionComponentTest extends TestCase
public void testNonPropagatingTxn() throws Exception
{
// start a transaction
- UserTransaction txnOuter = transactionComponent.getUserTransaction();
+ UserTransaction txnOuter = transactionService.getUserTransaction();
txnOuter.begin();
String txnIdOuter = AlfrescoTransactionSupport.getTransactionId();
// start a propagating txn
- UserTransaction txnInner = transactionComponent.getNonPropagatingUserTransaction();
+ UserTransaction txnInner = transactionService.getNonPropagatingUserTransaction();
txnInner.begin();
String txnIdInner = AlfrescoTransactionSupport.getTransactionId();
@@ -119,9 +121,9 @@ public class TransactionComponentTest extends TestCase
public void testReadOnlyTxn() throws Exception
{
// start a read-only transaction
- transactionComponent.setAllowWrite(false);
+ transactionService.setAllowWrite(false);
- UserTransaction txn = transactionComponent.getUserTransaction();
+ UserTransaction txn = transactionService.getUserTransaction();
txn.begin();
// do some writing
@@ -135,8 +137,39 @@ public class TransactionComponentTest extends TestCase
}
catch (InvalidDataAccessApiUsageException e)
{
+ @SuppressWarnings("unused")
int i = 0;
// expected
}
}
+
+ public void testGetRetryingTransactionHelper()
+ {
+ RetryingTransactionCallback