/* * Copyright (C) 2005-2007 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.sql.BatchUpdateException; import java.sql.SQLException; import java.util.Random; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.UserTransaction; import net.sf.ehcache.distribution.RemoteCacheException; 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.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.ObjectNotFoundException; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DeadlockLoserDataAccessException; import org.springframework.jdbc.UncategorizedSQLException; /** * A helper that runs a unit of work inside a UserTransaction, * transparently retrying the unit of work if the cause of * failure is an optimistic locking or deadlock condition. *
* Defaults: *
* To get details of 'why' transactions are retried use the following log level:
* If there is already an active transaction, then the callback is merely
* executed and any retry logic is left to the caller. The transaction
* will attempt to be read-write.
*
* @param cb The callback containing the unit of work.
* @return Returns the result of the unit of work.
* @throws RuntimeException all checked exceptions are converted
*/
public
* If there is already an active transaction, then the callback is merely
* executed and any retry logic is left to the caller.
*
* @param cb The callback containing the unit of work.
* @param readOnly Whether this is a read only transaction.
* @return Returns the result of the unit of work.
* @throws RuntimeException all checked exceptions are converted
*/
public
* It is possible to force a new transaction to be created or to partake in
* any existing transaction.
*
* @param cb The callback containing the unit of work.
* @param readOnly Whether this is a read only transaction.
* @param requiresNew true to force a new transaction or
* false to partake in any existing transaction.
* @return Returns the result of the unit of work.
* @throws RuntimeException all checked exceptions are converted
*/
public
* Summary: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=INFO
* Details: log4j.logger.org.alfresco.repo.transaction.RetryingTransactionHelper=DEBUG
*
*
* @author Derek Hulley
*/
public class RetryingTransactionHelper
{
private static final String MSG_READ_ONLY = "permissions.err_read_only";
private static Log logger = LogFactory.getLog(RetryingTransactionHelper.class);
/**
* Exceptions that trigger retries.
*/
@SuppressWarnings("unchecked")
public static final Class[] RETRY_EXCEPTIONS;
static
{
RETRY_EXCEPTIONS = new Class[] {
ConcurrencyFailureException.class,
DeadlockLoserDataAccessException.class,
StaleObjectStateException.class,
LockAcquisitionException.class,
ConstraintViolationException.class,
UncategorizedSQLException.class,
SQLException.class,
BatchUpdateException.class,
DataIntegrityViolationException.class,
StaleStateException.class,
ObjectNotFoundException.class,
RemoteCacheException.class
};
}
/**
* Reference to the TransactionService instance.
*/
private TransactionService txnService;
/** The maximum number of retries. -1 for infinity. */
private int maxRetries;
/** The minimum time to wait between retries. */
private int minRetryWaitMs;
/** The maximum time to wait between retries. */
private int maxRetryWaitMs;
/** How much to increase the wait time with each retry. */
private int retryWaitIncrementMs;
/**
* Whether the the transactions may only be reads
*/
private boolean readOnly;
/**
* Random number generator for retry delays.
*/
private Random random;
/**
* Callback interface
* @author britt
*/
public interface RetryingTransactionCallback