001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: XAEnvironment.java,v 1.8.2.4 2008/01/07 15:14:08 cwl Exp $
007: */
008:
009: package com.sleepycat.je;
010:
011: import java.io.File;
012:
013: import javax.transaction.xa.XAException;
014: import javax.transaction.xa.XAResource;
015: import javax.transaction.xa.Xid;
016:
017: import com.sleepycat.je.txn.Txn;
018: import com.sleepycat.je.txn.TxnManager;
019:
020: /**
021: * Javadoc for this public class is generated
022: * via the doc templates in the doc_src directory.
023: */
024: public class XAEnvironment extends Environment implements XAResource {
025:
026: private static final boolean DEBUG = false;
027:
028: /**
029: * Javadoc for this public method is generated via
030: * the doc templates in the doc_src directory.
031: */
032: public XAEnvironment(File envHome, EnvironmentConfig configuration)
033: throws DatabaseException {
034:
035: super (envHome, configuration);
036: }
037:
038: /**
039: * Used to get the Transaction object given an XA Xid.
040: */
041: public Transaction getXATransaction(Xid xid)
042: throws DatabaseException {
043:
044: Txn ret = environmentImpl.getTxnManager().getTxnFromXid(xid);
045: if (ret == null) {
046: return null;
047: }
048: /* Do we guarantee object identity for Transaction objects? */
049: return new Transaction(this , ret);
050: }
051:
052: /**
053: * Used to set the Transaction object for an XA Xid. Public for tests.
054: */
055: public void setXATransaction(Xid xid, Transaction txn)
056: throws DatabaseException {
057:
058: environmentImpl.getTxnManager().registerXATxn(xid,
059: txn.getTxn(), false);
060: }
061:
062: /*
063: * XAResource methods.
064: */
065:
066: /**
067: * Javadoc for this public method is generated via
068: * the doc templates in the doc_src directory.
069: */
070: public void commit(Xid xid, boolean ignore /*onePhase*/)
071: throws XAException {
072:
073: if (DEBUG) {
074: System.out.println("*** commit called " + xid + "/"
075: + ignore);
076: }
077:
078: if (xid == null) {
079: return;
080: }
081:
082: try {
083: checkEnv();
084: Transaction txn = getXATransaction(xid);
085: if (txn == null) {
086: throw new XAException("No transaction found for " + xid
087: + " during commit.");
088: }
089: removeReferringHandle(txn);
090: if (txn.getTxn().getOnlyAbortable()) {
091: throw new XAException(XAException.XA_RBROLLBACK);
092: }
093: txn.getTxn().commit(xid);
094: } catch (DatabaseException DE) {
095: throwNewXAException(DE);
096: }
097: if (DEBUG) {
098: System.out.println("*** commit finished");
099: }
100: }
101:
102: /**
103: * Javadoc for this public method is generated via
104: * the doc templates in the doc_src directory.
105: */
106: public void end(Xid xid, int flags) throws XAException {
107:
108: if (DEBUG) {
109: System.out.println("*** end called " + xid + "/" + flags);
110: }
111:
112: /* flags - One of TMSUCCESS, TMFAIL, or TMSUSPEND. */
113:
114: boolean tmFail = (flags & XAResource.TMFAIL) != 0;
115: boolean tmSuccess = (flags & XAResource.TMSUCCESS) != 0;
116: boolean tmSuspend = (flags & XAResource.TMSUSPEND) != 0;
117: if ((tmFail && tmSuccess)
118: || ((tmFail || tmSuccess) && tmSuspend)) {
119: throw new XAException(XAException.XAER_INVAL);
120: }
121:
122: try {
123: if (DEBUG) {
124: System.out.println("Transaction for "
125: + Thread.currentThread()
126: + " is "
127: + environmentImpl.getTxnManager()
128: .getTxnForThread());
129: }
130:
131: Transaction txn = environmentImpl.getTxnManager()
132: .unsetTxnForThread();
133: if (txn == null) {
134: txn = getXATransaction(xid);
135: boolean isSuspended = (txn != null)
136: && txn.getTxn().isSuspended();
137: if (!isSuspended) {
138: throw new XAException(XAException.XAER_NOTA);
139: }
140: }
141:
142: if (tmFail) {
143: txn.getTxn().setOnlyAbortable();
144: }
145:
146: if (tmSuspend) {
147: txn.getTxn().setSuspended(true);
148: }
149:
150: } catch (DatabaseException DE) {
151: throwNewXAException(DE);
152: }
153: }
154:
155: /**
156: * Javadoc for this public method is generated via
157: * the doc templates in the doc_src directory.
158: */
159: public void forget(Xid xid) throws XAException {
160:
161: if (DEBUG) {
162: System.out.println("*** forget called");
163: }
164:
165: throw new XAException(XAException.XAER_NOTA);
166: }
167:
168: /**
169: * Javadoc for this public method is generated via
170: * the doc templates in the doc_src directory.
171: */
172: public boolean isSameRM(XAResource rm) throws XAException {
173:
174: if (DEBUG) {
175: System.out.println("*** isSameRM called");
176: }
177:
178: try {
179: checkEnv();
180: } catch (DatabaseException DE) {
181: throwNewXAException(DE);
182: }
183:
184: if (rm == null) {
185: return false;
186: }
187:
188: if (!(rm instanceof XAEnvironment)) {
189: return false;
190: }
191:
192: return environmentImpl == DbInternal
193: .envGetEnvironmentImpl((XAEnvironment) rm);
194: }
195:
196: /**
197: * Javadoc for this public method is generated via
198: * the doc templates in the doc_src directory.
199: */
200: public int prepare(Xid xid) throws XAException {
201:
202: if (DEBUG) {
203: System.out.println("*** prepare called");
204: }
205:
206: try {
207: checkEnv();
208: Transaction txn = getXATransaction(xid);
209: if (txn == null) {
210: throw new XAException("No transaction found for " + xid
211: + " during prepare.");
212: }
213: int ret = txn.getTxn().prepare(xid);
214:
215: if (DEBUG) {
216: System.out.println("*** prepare returning " + ret);
217: }
218:
219: /*
220: * If this transaction was R/O, then there were no writes. We'll
221: * commit it here because the user doesn't need to (and isn't
222: * allowed to either).
223: */
224: if (ret == XAResource.XA_RDONLY) {
225: commit(xid, true);
226: }
227:
228: return ret;
229: } catch (DatabaseException DE) {
230: throwNewXAException(DE);
231: }
232: return XAResource.XA_OK; // for compiler
233: }
234:
235: /**
236: * Javadoc for this public method is generated via
237: * the doc templates in the doc_src directory.
238: */
239: public Xid[] recover(int flags) throws XAException {
240:
241: if (DEBUG) {
242: System.out.println("*** recover called");
243: }
244:
245: /* flags - One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. */
246:
247: boolean tmStartRScan = (flags & XAResource.TMSTARTRSCAN) != 0;
248: boolean tmEndRScan = (flags & XAResource.TMENDRSCAN) != 0;
249: if ((tmStartRScan && tmEndRScan)
250: || (!tmStartRScan && !tmEndRScan && flags != TMNOFLAGS)) {
251: throw new XAException(XAException.XAER_INVAL);
252: }
253:
254: /*
255: * We don't have to actually do anything with STARTRSCAN or ENDRSCAN
256: * since we return the whole set of Xid's to be recovered on each call.
257: */
258: try {
259: checkHandleIsValid();
260: checkEnv();
261:
262: if (DEBUG) {
263: System.out.println("*** recover returning1");
264: }
265:
266: return environmentImpl.getTxnManager().XARecover();
267: } catch (DatabaseException DE) {
268: throwNewXAException(DE);
269: }
270: return null; // for compiler
271: }
272:
273: /**
274: * Javadoc for this public method is generated via
275: * the doc templates in the doc_src directory.
276: */
277: public void rollback(Xid xid) throws XAException {
278:
279: if (DEBUG) {
280: System.out.println("*** rollback called");
281: }
282:
283: try {
284: checkEnv();
285: Transaction txn = getXATransaction(xid);
286: if (txn == null) {
287: throw new XAException("No transaction found for " + xid
288: + " during abort.");
289: }
290: removeReferringHandle(txn);
291: txn.getTxn().abort(xid);
292: } catch (DatabaseException DE) {
293: throwNewXAException(DE);
294: }
295:
296: if (DEBUG) {
297: System.out.println("*** rollback returning");
298: }
299: }
300:
301: /**
302: * Javadoc for this public method is generated via
303: * the doc templates in the doc_src directory.
304: */
305: public int getTransactionTimeout() throws XAException {
306:
307: try {
308: return (int) ((getConfig().getTxnTimeout() + 999999L) / 1000000L);
309: } catch (Exception DE) {
310: throwNewXAException(DE);
311: }
312: return 0; // for compiler
313: }
314:
315: /**
316: * Javadoc for this public method is generated via
317: * the doc templates in the doc_src directory.
318: */
319: public boolean setTransactionTimeout(int timeout)
320: throws XAException {
321:
322: return false;
323: }
324:
325: /**
326: * Javadoc for this public method is generated via
327: * the doc templates in the doc_src directory.
328: */
329: public void start(Xid xid, int flags) throws XAException {
330:
331: if (DEBUG) {
332: System.out.println("*** start called " + xid + "/" + flags);
333: }
334:
335: boolean tmJoin = (flags & XAResource.TMJOIN) != 0;
336: boolean tmResume = (flags & XAResource.TMRESUME) != 0;
337:
338: /* Check flags - only one of TMNOFLAGS, TMJOIN, or TMRESUME. */
339: if (xid == null
340: || (tmJoin && tmResume)
341: || (!tmJoin && !tmResume && flags != XAResource.TMNOFLAGS)) {
342: throw new XAException(XAException.XAER_INVAL);
343: }
344:
345: try {
346: Transaction txn = getXATransaction(xid);
347: TxnManager txnMgr = environmentImpl.getTxnManager();
348:
349: if (flags == XAResource.TMNOFLAGS) {
350:
351: /*
352: * If neither RESUME nor JOIN was set, make sure xid doesn't
353: * exist in allXATxns. Throw XAER_DUPID if it does.
354: */
355: if (txn == null) {
356: if (DEBUG) {
357: System.out.println("Transaction for XID " + xid
358: + " being created");
359: }
360:
361: txn = beginTransaction(null, null);
362: setXATransaction(xid, txn);
363:
364: } else {
365: throw new XAException(XAException.XAER_DUPID);
366: }
367: } else if (tmJoin) {
368: if (txn == null) {
369: throw new XAException(XAException.XAER_NOTA);
370: }
371:
372: if (txnMgr.getTxnForThread() != null
373: || txn.getPrepared()) {
374: throw new XAException(XAException.XAER_PROTO);
375: }
376: } else if (tmResume) {
377: if (txn == null) {
378: throw new XAException(XAException.XAER_NOTA);
379: }
380:
381: if (!txn.getTxn().isSuspended()) {
382: throw new XAException(XAException.XAER_PROTO);
383: }
384: txn.getTxn().setSuspended(false);
385: }
386:
387: if (DEBUG) {
388: System.out.println("Setting Transaction for "
389: + Thread.currentThread());
390: }
391: txnMgr.setTxnForThread(txn);
392: } catch (DatabaseException DE) {
393: if (DEBUG) {
394: System.out.println("*** start exception");
395: }
396: throwNewXAException(DE);
397: }
398:
399: if (DEBUG) {
400: System.out.println("*** start finished");
401: }
402: }
403:
404: private void throwNewXAException(Exception E) throws XAException {
405:
406: XAException ret = new XAException(E.toString());
407: ret.initCause(E);
408: throw ret;
409: }
410: }
|