/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/transaction/impl/IndexTransactionImpl.java $ * $Id: IndexTransactionImpl.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.search.transaction.impl; import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.search.indexer.api.IndexUpdateTransaction; import org.sakaiproject.search.transaction.api.IndexTransaction; import org.sakaiproject.search.transaction.api.IndexTransactionException; import org.sakaiproject.search.transaction.api.TransactionListener; /** * Base for index transactions * * @author ieb Unit test * @see org.sakaiproject.search.indexer.impl.test.TransactionalIndexWorkerTest */ public abstract class IndexTransactionImpl implements IndexTransaction { private static final Log log = LogFactory.getLog(IndexTransactionImpl.class); protected long transactionId = -2; protected TransactionManagerImpl manager; protected int transactionState = IndexTransaction.STATUS_UNKNOWN; private Map<String, Object> attributes; /** * @param m * @param impl * @throws IndexTransactionException */ public IndexTransactionImpl(TransactionManagerImpl manager, Map<String, Object> m) { this.manager = manager; attributes = m; } /** * * */ public void open() throws IndexTransactionException { transactionState = IndexTransaction.STATUS_NO_TRANSACTION; transactionId = manager.getSequence().getLocalId(); transactionState = IndexTransaction.STATUS_ACTIVE; doBeforeOpen(); fireOpen(this); doAfterOpen(); } /** * */ protected void doAfterOpen() { } /** * */ protected void doBeforeOpen() { } /** * @throws IndexTransactionException * @see org.sakaiproject.search.component.service.index.transactional.api.IndexUpdateTransaction#close() */ public final void close() throws IndexTransactionException { if (transactionState != IndexTransaction.STATUS_NO_TRANSACTION && transactionState != IndexTransaction.STATUS_COMMITTED && transactionState != IndexTransaction.STATUS_UNKNOWN) { try { rollback(); } catch (IndexTransactionException e) { log.debug(e); } doBeforeClose(); fireClose(this); doAfterClose(); } transactionState = IndexTransaction.STATUS_UNKNOWN; } /** * */ protected void doAfterClose() throws IndexTransactionException { } /** * */ protected void doBeforeClose() throws IndexTransactionException { } /** * @see org.sakaiproject.search.indexer.api.IndexUpdateTransaction#prepare() */ public final void prepare() throws IndexTransactionException { if (transactionState != IndexTransaction.STATUS_ACTIVE) { throw new IndexTransactionException("Transaction is not active "); } try { transactionState = IndexTransaction.STATUS_PREPARING; doBeforePrepare(); firePrepare(this); doAfterPrepare(); transactionState = IndexUpdateTransaction.STATUS_PREPARED; } catch (IndexTransactionException itex) { throw itex; } catch (Exception e) { throw new IndexTransactionException("Failed to prepare ", e); } } /** * */ protected void doAfterPrepare() throws IndexTransactionException { } /** * */ protected void doBeforePrepare() throws IndexTransactionException { } /** * @see org.sakaiproject.search.component.service.index.transactional.api.IndexUpdateTransaction#commit() */ public final void commit() throws IndexTransactionException { if (transactionState != IndexTransaction.STATUS_PREPARED) { throw new IndexTransactionException("Transaction is not prepared "); } try { transactionState = IndexTransaction.STATUS_COMMITTING; doBeforeCommit(); fireCommit(this); doAfterCommit(); transactionId = -1; transactionState = IndexTransaction.STATUS_COMMITTED; } catch (Exception e) { throw new IndexTransactionException("Failed to commit ", e); } } /** * */ protected void doAfterCommit() throws IndexTransactionException { } /** * */ protected void doBeforeCommit() throws IndexTransactionException { } /** * The transaction ID will change as the status cahnges. While the * transaction is active it will have a local ID, when the transaction is * prepared the cluster wide transaction id will be created. Once prepare * has been performed, the transaction should be committed * * @see org.sakaiproject.search.component.service.index.transactional.api.IndexUpdateTransaction#getTransactionId() */ public long getTransactionId() { return transactionId; } /** * @see org.sakaiproject.search.component.service.index.transactional.api.IndexUpdateTransaction#rollback() */ public final void rollback() throws IndexTransactionException { if (transactionState != IndexTransaction.STATUS_ACTIVE && transactionState != IndexTransaction.STATUS_COMMITTING && transactionState != IndexTransaction.STATUS_MARKED_ROLLBACK && transactionState != IndexTransaction.STATUS_PREPARED && transactionState != IndexTransaction.STATUS_PREPARING && transactionState != IndexTransaction.STATUS_ROLLING_BACK) { throw new IndexTransactionException( "Transaction cannot be rolled back, state not active, commtting, marked rolled bac, prepared, preparing or rollingback "); } try { transactionState = IndexTransaction.STATUS_ROLLING_BACK; doBeforeRollback(); fireRollback(this); doAfterRollback(); transactionId = -1; transactionState = IndexTransaction.STATUS_ROLLEDBACK; } catch (Exception e) { log.warn("Failed to roll back transaction ", e); } log.debug("Transaction Rollback Completed on " + this); } /** * */ protected void doAfterRollback() throws IndexTransactionException { } /** * */ protected void doBeforeRollback() throws IndexTransactionException { } /** * @see org.sakaiproject.search.indexer.api.IndexUpdateTransaction#getStatus() */ public final int getStatus() { return transactionState; } /** * @see org.sakaiproject.search.indexer.api.IndexUpdateTransaction#clear(java.lang.String) */ public void clear(String key) { attributes.remove(key); } /** * @see org.sakaiproject.search.indexer.api.IndexUpdateTransaction#get(java.lang.String) */ public Object get(String key) { return attributes.get(key); } /** * @see org.sakaiproject.search.indexer.api.IndexUpdateTransaction#put(java.lang.String, * java.lang.Object) */ public void put(String key, Object obj) { attributes.put(key, obj); } private void firePrepare(IndexTransaction transaction) throws IndexTransactionException { for (Iterator<TransactionListener> itl = manager.getTransactionListeners() .iterator(); itl.hasNext();) { TransactionListener tl = itl.next(); tl.prepare(transaction); } } private void fireCommit(IndexTransaction transaction) throws IndexTransactionException { for (Iterator<TransactionListener> itl = manager.getTransactionListeners() .iterator(); itl.hasNext();) { TransactionListener tl = itl.next(); tl.commit(transaction); } } /** * @param impl * @throws IndexTransactionException */ private void fireClose(IndexTransaction transaction) throws IndexTransactionException { for (Iterator<TransactionListener> itl = manager.getTransactionListeners() .iterator(); itl.hasNext();) { TransactionListener tl = itl.next(); tl.close(transaction); } } private void fireRollback(IndexTransaction transaction) throws IndexTransactionException { for (Iterator<TransactionListener> itl = manager.getTransactionListeners() .iterator(); itl.hasNext();) { TransactionListener tl = itl.next(); tl.rollback(transaction); } } private void fireOpen(IndexTransaction transaction) throws IndexTransactionException { for (Iterator<TransactionListener> itl = manager.getTransactionListeners() .iterator(); itl.hasNext();) { TransactionListener tl = itl.next(); tl.open(transaction); } } }