001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.ra;
018
019import javax.jms.JMSException;
020import javax.resource.ResourceException;
021import javax.resource.spi.LocalTransaction;
022import javax.transaction.xa.XAException;
023import javax.transaction.xa.XAResource;
024import javax.transaction.xa.Xid;
025
026import org.apache.activemq.TransactionContext;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030/**
031 * Used to provide a LocalTransaction and XAResource to a JMS session.
032 */
033public class LocalAndXATransaction implements XAResource, LocalTransaction {
034    private static final Logger LOG = LoggerFactory.getLogger(LocalAndXATransaction.class);
035
036    private TransactionContext transactionContext;
037    private boolean inManagedTx;
038
039    public LocalAndXATransaction(TransactionContext transactionContext) {
040        this.transactionContext = transactionContext;
041    }
042
043    public void setTransactionContext(TransactionContext transactionContext) {
044        this.transactionContext = transactionContext;
045    }
046
047    public void setInManagedTx(boolean inManagedTx) throws JMSException {
048        this.inManagedTx = inManagedTx;
049        if (!inManagedTx) {
050            transactionContext.cleanup();
051        }
052    }
053
054    public void begin() throws ResourceException {
055        try {
056            transactionContext.begin();
057            setInManagedTx(true);
058        } catch (JMSException e) {
059            throw new ResourceException("begin failed.", e);
060        }
061    }
062
063    public void commit() throws ResourceException {
064        try {
065            transactionContext.commit();
066        } catch (JMSException e) {
067            throw new ResourceException("commit failed.", e);
068        } finally {
069            try {
070                setInManagedTx(false);
071            } catch (JMSException e) {
072                throw new ResourceException("commit failed.", e);
073            }
074        }
075    }
076
077    public void rollback() throws ResourceException {
078        try {
079            transactionContext.rollback();
080        } catch (JMSException e) {
081            throw new ResourceException("rollback failed.", e);
082        } finally {
083            try {
084                setInManagedTx(false);
085            } catch (JMSException e) {
086                throw new ResourceException("rollback failed.", e);
087            }
088        }
089    }
090
091    public void commit(Xid arg0, boolean arg1) throws XAException {
092        transactionContext.commit(arg0, arg1);
093    }
094
095    public void end(Xid arg0, int arg1) throws XAException {
096        LOG.debug("{} end {} with {}", new Object[]{this, arg0, arg1});
097        try {
098            transactionContext.end(arg0, arg1);
099        } finally {
100            try {
101                setInManagedTx(false);
102            } catch (JMSException e) {
103                throw (XAException)new XAException(XAException.XAER_PROTO).initCause(e);
104            }
105        }
106    }
107
108    public void forget(Xid arg0) throws XAException {
109        transactionContext.forget(arg0);
110    }
111
112    public int getTransactionTimeout() throws XAException {
113        return transactionContext.getTransactionTimeout();
114    }
115
116    public boolean isSameRM(XAResource xaresource) throws XAException {
117        boolean isSame = false;
118        if (xaresource != null) {
119            // Do we have to unwrap?
120            if (xaresource instanceof LocalAndXATransaction) {
121                xaresource = ((LocalAndXATransaction)xaresource).transactionContext;
122            }
123            isSame = transactionContext.isSameRM(xaresource);
124        }
125        LOG.trace("{} isSameRM({}) = {}", new Object[]{this, xaresource, isSame});
126        return isSame;
127    }
128
129    public int prepare(Xid arg0) throws XAException {
130        return transactionContext.prepare(arg0);
131    }
132
133    public Xid[] recover(int arg0) throws XAException {
134        Xid[] answer = null;
135        LOG.trace("{} recover({})", new Object[]{this, arg0});
136        answer = transactionContext.recover(arg0);
137        LOG.trace("{} recover({}) = {}", new Object[]{this, arg0, answer});
138        return answer;
139    }
140
141    public void rollback(Xid arg0) throws XAException {
142        transactionContext.rollback(arg0);
143    }
144
145    public boolean setTransactionTimeout(int arg0) throws XAException {
146        return transactionContext.setTransactionTimeout(arg0);
147    }
148
149    public void start(Xid arg0, int arg1) throws XAException {
150        LOG.trace("{} start {} with {}", new Object[]{this, arg0, arg1});
151        transactionContext.start(arg0, arg1);
152        try {
153            setInManagedTx(true);
154        } catch (JMSException e) {
155            throw (XAException)new XAException(XAException.XAER_PROTO).initCause(e);
156        }
157    }
158
159    public boolean isInManagedTx() {
160        return inManagedTx;
161    }
162
163    public void cleanup() {
164        transactionContext.cleanup();
165        inManagedTx = false;
166    }
167
168    @Override
169    public String toString() {
170        return "[" + super.toString() + "," + transactionContext + "]";
171    }
172}