Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright 2003-2010 Terracotta, Inc.
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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 net.sf.ehcache.transaction.xa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import javax.transaction.RollbackException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.concurrent.CacheLockProvider;
import net.sf.ehcache.concurrent.LockType;
import net.sf.ehcache.concurrent.Sync;
import net.sf.ehcache.hibernate.tm.SyncTransactionManager;
import net.sf.ehcache.store.Store;
import net.sf.ehcache.transaction.TransactionContext;
import net.sf.ehcache.transaction.xa.XARequest.RequestType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Default implementation for EhcacheXAResource.
* It encapsulates the store to be accessed in a transactional way, the TransactionManager
* and an {@link net.sf.ehcache.transaction.xa.EhcacheXAStore EhcacheXAStore}, where it'll save transaction data during
* the two-phase commit process, and between suspend/resume transaction cycles.
*
* It'll also associate {@link javax.transaction.Transaction Transaction} instances with their {@link javax.transaction.xa.Xid Xid}
*
* @author Nabib El-Rahman
* @author Alex Snaps
*/
public class EhcacheXAResourceImpl implements EhcacheXAResource {
private static final int LOCK_TIMEOUT = 15000;
private static final int DEFAULT_TX_TIMEOUT = 60;
private static final int MILLISEC_PER_SECOND = 1000;
private static final Logger LOG = LoggerFactory.getLogger(EhcacheXAResourceImpl.class.getName());
private final String cacheName;
private final XARequestProcessor processor;
private final EhcacheXAStore ehcacheXAStore;
private final Store store;
private final Store oldVersionStore;
private final TransactionManager txnManager;
private final Ehcache cache;
private final Set recoverySet = new HashSet();
private final boolean bypassValidation;
private volatile int transactionTimeout = DEFAULT_TX_TIMEOUT;
private volatile Xid currentXid;
private List twoPcExecutionListeners = new ArrayList();
/**
* Constructor
*
* @param cache
* The cache name of the Cache wrapped
* @param txnManager
* the TransactionManager associated with this XAResource
* @param ehcacheXAStore
* The EhcacheXAStore for this cache
*/
public EhcacheXAResourceImpl(Ehcache cache, TransactionManager txnManager, EhcacheXAStore ehcacheXAStore) {
String cacheMgrName;
if (cache.getCacheManager() == null || !cache.getCacheManager().isNamed()) {
cacheMgrName = CacheManager.DEFAULT_NAME;
} else {
cacheMgrName = cache.getCacheManager().getName();
}
this.cacheName = cache.getName() + "@" + cacheMgrName + ".cacheManager";
this.store = ehcacheXAStore.getUnderlyingStore();
this.txnManager = txnManager;
this.ehcacheXAStore = ehcacheXAStore;
this.oldVersionStore = ehcacheXAStore.getOldVersionStore();
this.cache = cache;
this.processor = new TransactionXARequestProcessor(this);
this.bypassValidation = txnManager instanceof SyncTransactionManager;
}
/**
* {@inheritDoc}
*/
public void addTwoPcExecutionListener(TwoPcExecutionListener listener) {
twoPcExecutionListeners.add(listener);
}
/**
* {@inheritDoc}
*/
public String getCacheName() {
return cacheName;
}
/**
* {@inheritDoc}
*/
public void start(final Xid xid, final int flags) throws XAException {
//todo: check flags, do not allow 2X start()
if (LOG.isDebugEnabled()) {
LOG.debug("xaResource.start called for Txn with flag: " + prettyPrintFlags(flags) + " and id: " + xid);
}
currentXid = xid;
}
/**
* {@inheritDoc}
*/
public void end(final Xid xid, final int flags) throws XAException {
//todo: check flags, throw an exception if start() was not called
if (LOG.isDebugEnabled()) {
LOG.debug("xaResource.end called for Txn with flag: " + prettyPrintFlags(flags) + " and id: " + xid);
}
if (isFlagSet(flags, TMFAIL)) {
if (ehcacheXAStore.isPrepared(xid)) {
// todo: throw protocol violation!
markContextAsRolledbackIfRecovered(xid);
} else {
ehcacheXAStore.removeData(xid);
}
}
currentXid = null;
}
/**
* {@inheritDoc}
*/
public int prepare(final Xid xid) throws XAException {
//todo: check XID, throw an exception if end() not called or if start()/end() never called
for (TwoPcExecutionListener twoPcExecutionListener : twoPcExecutionListeners) {
try {
twoPcExecutionListener.beforePrepare(this);
} catch (RuntimeException ex) {
LOG.warn("exception thrown before prepare in TwoPcExecutionListener " + twoPcExecutionListener, ex);
}
}
return this.processor.process(new XARequest(RequestType.PREPARE, getCurrentTransaction(), xid, XAResource.TMNOFLAGS));
}
/**
* Called by {@link XARequestProcessor}
* @param xid the Xid of the transaction to prepare
* @return XA_OK, or XA_RDONLY if no write operations prepared
* @throws XAException if an integrity issue occurs
*/
int prepareInternal(final Xid xid) throws XAException {
if (LOG.isDebugEnabled()) {
LOG.debug("xaResource.prepare called for Txn with id: " + xid);
}
TransactionContext context = ehcacheXAStore.getTransactionContext(xid);
CacheLockProvider storeLockProvider = (CacheLockProvider) store.getInternalContext();
CacheLockProvider oldVersionStoreLockProvider = (CacheLockProvider) oldVersionStore.getInternalContext();
// Lock all keys in both stores
Object[] updatedKeys = context.getUpdatedKeys();
tryLockingKeysRequiredForPrepare(storeLockProvider, oldVersionStoreLockProvider, updatedKeys);
try {
// validate we will be able to commit
validateCommands(context, xid);
} catch (XAException e) {
// If something goes wrong
cleanUpFailure(xid, storeLockProvider, oldVersionStoreLockProvider, updatedKeys);
throw e;
}
PreparedContext preparedContext = ehcacheXAStore.createPreparedContext();
// Copy old versions in front-accessed store todo crappy coupling going on here!
for (VersionAwareCommand command : context.getCommands()) {
// as we only have write commands to specific keys here... but this could change, and we'd try to unlock non-locked keys
Object key = command.getKey();
if (key != null) {
oldVersionStore.put(store.get(command.getKey()));
preparedContext.addCommand(command);
}
}
oldVersionStoreLockProvider.unlockWriteLockForAllKeys(updatedKeys);
// Execute write command within the real underlying store
boolean writes = false;
Set