001: /*
002: * $Id: DefaultXASession.java 8077 2007-08-27 20:15:25Z aperepel $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.util.xa;
012:
013: import javax.transaction.Status;
014: import javax.transaction.xa.XAException;
015: import javax.transaction.xa.XAResource;
016: import javax.transaction.xa.Xid;
017:
018: import org.apache.commons.logging.Log;
019: import org.apache.commons.logging.LogFactory;
020:
021: /**
022: * TODO document
023: */
024: public class DefaultXASession implements XAResource {
025:
026: /**
027: * logger used by this class
028: */
029: protected transient Log logger = LogFactory.getLog(getClass());
030:
031: protected AbstractTransactionContext localContext;
032: protected Xid localXid;
033: protected AbstractXAResourceManager resourceManager;
034:
035: public DefaultXASession(AbstractXAResourceManager resourceManager) {
036: this .localContext = null;
037: this .localXid = null;
038: this .resourceManager = resourceManager;
039: }
040:
041: public XAResource getXAResource() {
042: return this ;
043: }
044:
045: public Object getResourceManager() {
046: return resourceManager;
047: }
048:
049: //
050: // Local transaction implementation
051: //
052: public void begin() throws ResourceManagerException {
053: if (localXid != null) {
054: throw new IllegalStateException(
055: "Cannot start local transaction. An XA transaction is already in progress.");
056: }
057: if (localContext != null) {
058: throw new IllegalStateException(
059: "Cannot start local transaction. A local transaction already in progress.");
060: }
061: localContext = resourceManager.createTransactionContext(this );
062: resourceManager.beginTransaction(localContext);
063: }
064:
065: public void commit() throws ResourceManagerException {
066: if (localXid != null) {
067: throw new IllegalStateException(
068: "Cannot commit local transaction as an XA transaction is in progress.");
069: }
070: if (localContext == null) {
071: throw new IllegalStateException(
072: "Cannot commit local transaction as no transaction was begun");
073: }
074: resourceManager.commitTransaction(localContext);
075: localContext = null;
076: }
077:
078: public void rollback() throws ResourceManagerException {
079: if (localXid != null) {
080: throw new IllegalStateException(
081: "Cannot rollback local transaction as an XA transaction is in progress.");
082: }
083: if (localContext == null) {
084: throw new IllegalStateException(
085: "Cannot commit local transaction as no transaction was begun");
086: }
087: resourceManager.rollbackTransaction(localContext);
088: localContext = null;
089: }
090:
091: //
092: // XAResource implementation
093: //
094:
095: public boolean isSameRM(XAResource xares) throws XAException {
096: return xares instanceof DefaultXASession
097: && ((DefaultXASession) xares).getResourceManager()
098: .equals(resourceManager);
099: }
100:
101: public Xid[] recover(int flag) throws XAException {
102: return null;
103: }
104:
105: public void start(Xid xid, int flags) throws XAException {
106: if (logger.isDebugEnabled()) {
107: logger.debug(new StringBuffer(128).append("Thread ")
108: .append(Thread.currentThread()).append(
109: flags == TMNOFLAGS ? " starts"
110: : flags == TMJOIN ? " joins"
111: : " resumes").append(
112: " work on behalf of transaction branch ")
113: .append(xid).toString());
114: }
115: // A local transaction is already begun
116: if (this .localContext != null) {
117: throw new XAException(XAException.XAER_PROTO);
118: }
119: // This session has already been associated with an xid
120: if (this .localXid != null) {
121: throw new XAException(XAException.XAER_PROTO);
122: }
123: switch (flags) {
124: // a new transaction
125: case TMNOFLAGS:
126: case TMJOIN:
127: default:
128: try {
129: localContext = resourceManager
130: .createTransactionContext(this );
131: resourceManager.beginTransaction(localContext);
132: } catch (Exception e) {
133: // TODO MULE-863: Is logging necessary?
134: logger.error(
135: "Could not create new transactional resource",
136: e);
137: throw (XAException) new XAException(e.getMessage())
138: .initCause(e);
139: }
140: break;
141: case TMRESUME:
142: localContext = resourceManager
143: .getSuspendedTransactionalResource(xid);
144: if (localContext == null) {
145: throw new XAException(XAException.XAER_NOTA);
146: }
147: // TODO: resume context
148: resourceManager.removeSuspendedTransactionalResource(xid);
149: break;
150: }
151: localXid = xid;
152: resourceManager.addActiveTransactionalResource(localXid,
153: localContext);
154: }
155:
156: public void end(Xid xid, int flags) throws XAException {
157: if (logger.isDebugEnabled()) {
158: logger.debug(new StringBuffer(128).append("Thread ")
159: .append(Thread.currentThread()).append(
160: flags == TMSUSPEND ? " suspends"
161: : flags == TMFAIL ? " fails"
162: : " ends").append(
163: " work on behalf of transaction branch ")
164: .append(xid).toString());
165: }
166: // No transaction is already begun
167: if (localContext == null) {
168: throw new XAException(XAException.XAER_NOTA);
169: }
170: // This session has already been associated with an xid
171: if (localXid == null || !localXid.equals(xid)) {
172: throw new XAException(XAException.XAER_PROTO);
173: }
174:
175: try {
176: switch (flags) {
177: case TMSUSPEND:
178: // TODO: suspend context
179: resourceManager.addSuspendedTransactionalResource(
180: localXid, localContext);
181: resourceManager
182: .removeActiveTransactionalResource(localXid);
183: break;
184: case TMFAIL:
185: resourceManager
186: .setTransactionRollbackOnly(localContext);
187: break;
188: case TMSUCCESS: // no-op
189: default: // no-op
190: break;
191: }
192: } catch (ResourceManagerException e) {
193: throw (XAException) new XAException(XAException.XAER_RMERR)
194: .initCause(e);
195: }
196: localXid = null;
197: localContext = null;
198: }
199:
200: public void commit(Xid xid, boolean onePhase) throws XAException {
201: if (xid == null) {
202: throw new XAException(XAException.XAER_PROTO);
203: }
204: AbstractTransactionContext context = resourceManager
205: .getActiveTransactionalResource(xid);
206: if (context == null) {
207: throw new XAException(XAException.XAER_NOTA);
208: }
209: if (logger.isDebugEnabled()) {
210: logger.debug("Committing transaction branch " + xid);
211: }
212: if (context.status == Status.STATUS_MARKED_ROLLBACK) {
213: throw new XAException(XAException.XA_RBROLLBACK);
214: }
215:
216: try {
217: if (context.status != Status.STATUS_PREPARED) {
218: if (onePhase) {
219: resourceManager.prepareTransaction(context);
220: } else {
221: throw new XAException(XAException.XAER_PROTO);
222: }
223: }
224: resourceManager.commitTransaction(context);
225: } catch (ResourceManagerException e) {
226: throw (XAException) new XAException(XAException.XAER_RMERR)
227: .initCause(e);
228: }
229: resourceManager.removeActiveTransactionalResource(xid);
230: resourceManager.removeSuspendedTransactionalResource(xid);
231: }
232:
233: public void rollback(Xid xid) throws XAException {
234: if (xid == null) {
235: throw new XAException(XAException.XAER_PROTO);
236: }
237: AbstractTransactionContext context = resourceManager
238: .getActiveTransactionalResource(xid);
239: if (context == null) {
240: throw new XAException(XAException.XAER_NOTA);
241: }
242: if (logger.isDebugEnabled()) {
243: logger.debug("Rolling back transaction branch " + xid);
244: }
245: try {
246: resourceManager.rollbackTransaction(context);
247: } catch (ResourceManagerException e) {
248: throw (XAException) new XAException(XAException.XAER_RMERR)
249: .initCause(e);
250: }
251: resourceManager.removeActiveTransactionalResource(xid);
252: resourceManager.removeSuspendedTransactionalResource(xid);
253: }
254:
255: public int prepare(Xid xid) throws XAException {
256: if (xid == null) {
257: throw new XAException(XAException.XAER_PROTO);
258: }
259:
260: AbstractTransactionContext context = resourceManager
261: .getTransactionalResource(xid);
262: if (context == null) {
263: throw new XAException(XAException.XAER_NOTA);
264: }
265:
266: if (logger.isDebugEnabled()) {
267: logger.debug("Preparing transaction branch " + xid);
268: }
269:
270: if (context.status == Status.STATUS_MARKED_ROLLBACK) {
271: throw new XAException(XAException.XA_RBROLLBACK);
272: }
273:
274: try {
275: return resourceManager.prepareTransaction(context);
276: } catch (ResourceManagerException e) {
277: throw (XAException) new XAException(XAException.XAER_RMERR)
278: .initCause(e);
279: }
280: }
281:
282: public void forget(Xid xid) throws XAException {
283: if (logger.isDebugEnabled()) {
284: logger.debug("Forgetting transaction branch " + xid);
285: }
286: AbstractTransactionContext context = resourceManager
287: .getTransactionalResource(xid);
288: if (context == null) {
289: throw new XAException(XAException.XAER_NOTA);
290: }
291: resourceManager.removeActiveTransactionalResource(xid);
292: resourceManager.removeSuspendedTransactionalResource(xid);
293: }
294:
295: /*
296: * (non-Javadoc)
297: *
298: * @see javax.transaction.xa.XAResource#getDefaultTransactionTimeout()
299: */
300: public int getTransactionTimeout() throws XAException {
301: return (int) (resourceManager.getDefaultTransactionTimeout() / 1000);
302: }
303:
304: /*
305: * (non-Javadoc)
306: *
307: * @see javax.transaction.xa.XAResource#setDefaultTransactionTimeout(int)
308: */
309: public boolean setTransactionTimeout(int timeout)
310: throws XAException {
311: resourceManager.setDefaultTransactionTimeout(timeout * 1000);
312: return false;
313: }
314:
315: }
|