Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.commons.transaction.util.xa; import java.util.HashMap; import java.util.Map; import java.util.Collections; import javax.transaction.Status; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.commons.transaction.util.LoggerFacade; /** * Abstract XAResource doing all the tedious tasks shared by many XAResouce implementations. * * @version $Id: AbstractXAResource.java 493628 2007-01-07 01:42:48Z joerg $ */ public abstract class AbstractXAResource implements XAResource, Status { // there might be at least one active transaction branch per thread private ThreadLocal activeTransactionBranch = new ThreadLocal(); private Map suspendedContexts = Collections.synchronizedMap(new HashMap()); private Map activeContexts = Collections.synchronizedMap(new HashMap()); public abstract boolean isSameRM(XAResource xares) throws XAException; public abstract Xid[] recover(int flag) throws XAException; protected abstract LoggerFacade getLoggerFacade(); protected abstract boolean includeBranchInXid(); public void forget(Xid xid) throws XAException { if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine("Forgetting transaction branch " + xid); } TransactionalResource ts = getTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } setCurrentlyActiveTransactionalResource(null); removeActiveTransactionalResource(xid); removeSuspendedTransactionalResource(xid); } public void commit(Xid xid, boolean onePhase) throws XAException { TransactionalResource ts = getTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine("Committing transaction branch " + ts); } if (ts.getStatus() == STATUS_MARKED_ROLLBACK) { throw new XAException(XAException.XA_RBROLLBACK); } if (ts.getStatus() != STATUS_PREPARED) { if (onePhase) { ts.prepare(); } else { throw new XAException(XAException.XAER_PROTO); } } ts.commit(); setCurrentlyActiveTransactionalResource(null); removeActiveTransactionalResource(xid); removeSuspendedTransactionalResource(xid); } public void rollback(Xid xid) throws XAException { TransactionalResource ts = getTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine("Rolling back transaction branch " + ts); } ts.rollback(); setCurrentlyActiveTransactionalResource(null); removeActiveTransactionalResource(xid); removeSuspendedTransactionalResource(xid); } public int prepare(Xid xid) throws XAException { TransactionalResource ts = getTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine("Preparing transaction branch " + ts); } if (ts.getStatus() == STATUS_MARKED_ROLLBACK) { throw new XAException(XAException.XA_RBROLLBACK); } int result = ts.prepare(); ts.setStatus(STATUS_PREPARED); if (result == XA_RDONLY) { commit(xid, false); } return result; } public void end(Xid xid, int flags) throws XAException { TransactionalResource ts = getActiveTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } if (getCurrentlyActiveTransactionalResource() == null) { throw new XAException(XAException.XAER_INVAL); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine(new StringBuffer(128).append("Thread ").append(Thread.currentThread()) .append(flags == TMSUSPEND ? " suspends" : flags == TMFAIL ? " fails" : " ends") .append(" work on behalf of transaction branch ").append(ts).toString()); } switch (flags) { case TMSUSPEND: ts.suspend(); addSuspendedTransactionalResource(xid, ts); removeActiveTransactionalResource(xid); break; case TMFAIL: ts.setStatus(STATUS_MARKED_ROLLBACK); break; case TMSUCCESS: break; } setCurrentlyActiveTransactionalResource(null); } public void start(Xid xid, int flags) throws XAException { if (getCurrentlyActiveTransactionalResource() != null) { throw new XAException(XAException.XAER_INVAL); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine(new StringBuffer(128).append("Thread ").append(Thread.currentThread()) .append(flags == TMNOFLAGS ? " starts" : flags == TMJOIN ? " joins" : " resumes") .append(" work on behalf of transaction branch ").append(xid).toString()); } TransactionalResource ts; switch (flags) { // a new transaction case TMNOFLAGS: case TMJOIN: default: try { ts = createTransactionResource(xid); ts.begin(); } catch (Exception e) { getLoggerFacade().logSevere("Could not create new transactional resource", e); throw new XAException(e.getMessage()); } break; case TMRESUME: ts = getSuspendedTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } ts.resume(); removeSuspendedTransactionalResource(xid); break; } setCurrentlyActiveTransactionalResource(ts); addAcitveTransactionalResource(xid, ts); } abstract protected TransactionalResource createTransactionResource(Xid xid) throws Exception; protected TransactionalResource getCurrentlyActiveTransactionalResource() { TransactionalResource context = (TransactionalResource) activeTransactionBranch.get(); return context; } protected void setCurrentlyActiveTransactionalResource(TransactionalResource context) { activeTransactionBranch.set(context); } protected TransactionalResource getTransactionalResource(Xid xid) { TransactionalResource ts = getActiveTransactionalResource(xid); if (ts != null) return ts; else return getSuspendedTransactionalResource(xid); } protected TransactionalResource getActiveTransactionalResource(Xid xid) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); return (TransactionalResource) activeContexts.get(wxid); } protected TransactionalResource getSuspendedTransactionalResource(Xid xid) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); return (TransactionalResource) suspendedContexts.get(wxid); } protected void addAcitveTransactionalResource(Xid xid, TransactionalResource txContext) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); activeContexts.put(wxid, txContext); } protected void addSuspendedTransactionalResource(Xid xid, TransactionalResource txContext) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); suspendedContexts.put(wxid, txContext); } protected void removeActiveTransactionalResource(Xid xid) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); activeContexts.remove(wxid); } protected void removeSuspendedTransactionalResource(Xid xid) { Xid wxid = XidWrapper.wrap(xid, includeBranchInXid()); suspendedContexts.remove(wxid); } }