001: /*
002:
003: Derby - Class org.apache.derby.impl.drda.DRDAXAProtocol.java
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: /**
023: * This class translates DRDA XA protocol from an application requester to XA
024: * calls for Derby and then translates the results from Derby to DRDA
025: * for return to the application requester.
026: * This class requires the use of javax.transaction.xa classes from j2ee,
027: * so is separated from DRDAConnThread, because of the additional
028: * library requirements
029: * @author kmarsden@Sourcery.Org
030: */package org.apache.derby.impl.drda;
031:
032: import org.apache.derby.iapi.services.sanity.SanityManager;
033: import javax.transaction.xa.*;
034:
035: class DRDAXAProtocol {
036:
037: private DRDAConnThread connThread;
038: private DDMReader reader;
039: private DDMWriter writer;
040:
041: DRDAXAProtocol(DRDAConnThread connThread) {
042: this .connThread = connThread;
043: reader = connThread.getReader();
044: writer = connThread.getWriter();
045:
046: }
047:
048: /**
049: * Parse SYNCCTL - Parse SYNCCTL command for XAMGR lvl 7
050: *
051: */
052: protected void parseSYNCCTL() throws DRDAProtocolException {
053:
054: reader.markCollection();
055:
056: int codePoint = reader.getCodePoint(CodePoint.SYNCTYPE);
057: int syncType = parseSYNCTYPE();
058:
059: int xaflags = 0;
060: boolean readXAFlags = false;
061: Xid xid = null;
062:
063: codePoint = reader.getCodePoint();
064: while (codePoint != -1) {
065: switch (codePoint) {
066: case CodePoint.XID:
067: xid = parseXID();
068: break;
069: case CodePoint.XAFLAGS:
070: xaflags = parseXAFlags();
071: readXAFlags = true;
072: break;
073: case CodePoint.TIMEOUT:
074: // optional/ignorable.
075: reader.skipBytes();
076: break;
077: case CodePoint.RLSCONV:
078: connThread.codePointNotSupported(codePoint);
079: default:
080: connThread.invalidCodePoint(codePoint);
081: }
082:
083: codePoint = reader.getCodePoint();
084: }
085:
086: {
087: connThread
088: .trace("syncType = " + syncTypeToString(syncType));
089: connThread.trace("xid = " + xid);
090: connThread.trace("xaflags =" + xaflagsToString(xaflags));
091: }
092:
093: if (syncType != CodePoint.SYNCTYPE_INDOUBT) {
094: if (xid == null)
095: connThread.missingCodePoint(CodePoint.XID);
096:
097: // All but Recover and forget require xaFlags
098: if (syncType != CodePoint.SYNCTYPE_REQ_FORGET
099: && !readXAFlags)
100: if (SanityManager.DEBUG)
101: connThread.missingCodePoint(CodePoint.XAFLAGS);
102: }
103:
104: switch (syncType) {
105: case CodePoint.SYNCTYPE_NEW_UOW:
106: // new unit of work for XA
107: // formatId -1 is just a local connection
108: startXATransaction(xid, xaflags);
109: break;
110: case CodePoint.SYNCTYPE_END_UOW:
111: // End unit of work
112: endXA(xid, xaflags);
113: break;
114: case CodePoint.SYNCTYPE_PREPARE:
115: prepareXATransaction(xid);
116: // Prepare to commit
117: break;
118: case CodePoint.SYNCTYPE_MIGRATE:
119: // migrate to resync server sync type
120: connThread.codePointNotSupported(codePoint);
121: break;
122: case CodePoint.SYNCTYPE_REQ_COMMIT:
123: // request to commit sync type
124: commitTransaction(xid, xaflags);
125: break;
126: case CodePoint.SYNCTYPE_COMMITTED:
127: // commit sync type
128: commitTransaction(xid, xaflags);
129: break;
130: case CodePoint.SYNCTYPE_REQ_FORGET:
131: // request to forget sync type
132: forgetXATransaction(xid);
133: break;
134: case CodePoint.SYNCTYPE_ROLLBACK:
135: //rollback sync type
136: rollbackTransaction(xid);
137: break;
138: case CodePoint.SYNCTYPE_INDOUBT:
139: //recover sync type
140: if (readXAFlags)
141: recoverXA(xaflags);
142: else
143: recoverXA();
144: break;
145: default:
146: connThread.invalidCodePoint(codePoint);
147: }
148:
149: }
150:
151: /**
152: * parse SYNCTYPE for XAMGR lvl 7
153: * return synctype value
154: * CodePoint.SYNCTYPE_NEW_UOW -> XAResource.start()
155: * CodePoint.SYNCTYPE_END_UOW -> XAResource.end()
156: * CodePoint.SYNCTYPE_PREPARE -> XAResource.prepare()
157: * CodePoint.SYNCTYPE_MIGRATE -> not supported //SYNCPT MGR LEVEL 5
158: * CodePoint.SYNCTYPE_REQ_COMMIT -> not supported //SYNCPT MGR LEVEL 5
159: * CodePoint.SYNCTYPE_COMMITTED -> XAResource.commit()
160: * or local commit for null XID
161: * CodePoint.SYNCTYPE_REQ_LOG -> not supported
162: * CodePoint.SYNCTYPE_REQ_FORGET -> XAResource.forget()
163: * CodePoint.SYNCTYPE_ROLLBACK -> XAResource.rollback()
164: * CodePoint.SYNCTYPE_MIGRATED -> not supported
165: * CodePoint.SYNCTYPE_INDOUBT -> XAResource.recover();
166: *
167: */
168: protected int parseSYNCTYPE() throws DRDAProtocolException {
169: return reader.readUnsignedByte();
170:
171: }
172:
173: /** Parse XID
174: * formatId -1 translates into a null XID and a local transaction
175: */
176: private Xid parseXID() throws DRDAProtocolException {
177: int formatId = reader.readNetworkInt();
178: byte[] gtrid = null;
179: byte[] bqual = null;
180: if (formatId != -1) {
181: int gtridLen = reader.readNetworkInt();
182: int bqualLen = reader.readNetworkInt();
183:
184: gtrid = reader.readBytes(gtridLen);
185: bqual = reader.readBytes(bqualLen);
186: }
187: return new DRDAXid(formatId, gtrid, bqual);
188: }
189:
190: /**
191: * parse XIDSHR
192: *
193: * @return XIDSHR value
194: * @throws DRDAProtocolException
195: */
196: private int parseXIDSHR() throws DRDAProtocolException {
197: return reader.readUnsignedByte();
198: }
199:
200: /**
201: * parse XAFlags
202: *
203: * @return XAFlags value
204: * @throws DRDAProtocolException
205: */
206: private int parseXAFlags() throws DRDAProtocolException {
207: return reader.readNetworkInt();
208: }
209:
210: /**
211: * Start the xa transaction. Send SYNCRRD response
212: *
213: * @param xid - XID (formatId = -1 for local transaction)
214: * @param xaflags - xaflags
215: * @throws DRDAProtocolException
216: */
217: private void startXATransaction(Xid xid, int xaflags)
218: throws DRDAProtocolException {
219: XAResource xaResource = getXAResource();
220: int xaRetVal = xaResource.XA_OK;
221:
222: try {
223: if (xid.getFormatId() != -1)
224: xaResource.start(xid, xaflags);
225: } catch (XAException xe) {
226: xaRetVal = processXAException(xe);
227: }
228: writeSYNCCRD(CodePoint.SYNCTYPE_NEW_UOW, xaRetVal, null);
229:
230: }
231:
232: /**
233: * Commit the xa transaction. Send SYNCCRD response
234: *
235: * @param xid - XID (formatId = -1 for local transaction)
236: * @param xaflags - xaflags
237: * @throws DRDAProtocolException
238: */
239: private void commitTransaction(Xid xid, int xaflags)
240: throws DRDAProtocolException {
241: boolean local = (xid.getFormatId() == -1);
242: if (local)
243: commitLocalTransaction();
244: else
245: commitXATransaction(xid, xaflags);
246: }
247:
248: /**
249: * Commit local transaction. Send SYNCCRD response.
250: *
251: * @throws DRDAProtocolException
252: */
253: private void commitLocalTransaction() throws DRDAProtocolException {
254: int xaRetVal = XAResource.XA_OK;
255: try {
256: connThread.getDatabase().commit();
257: } catch (Exception e) {
258: xaRetVal = XAException.XAER_RMFAIL;
259: if (SanityManager.DEBUG) {
260: connThread.getServer().consoleExceptionPrint(e);
261: }
262:
263: }
264: writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, xaRetVal, null);
265:
266: }
267:
268: /**
269: * Commit the xa transaction. Send SYNCCRD response.
270: *
271: * @param xid - XID
272: * @param xaflags - xaflags
273: * @throws DRDAProtocolException
274: */
275: private void commitXATransaction(Xid xid, int xaflags)
276: throws DRDAProtocolException {
277: XAResource xaResource = getXAResource();
278: int xaRetVal = xaResource.XA_OK;
279: // check this
280: boolean isOnePhase = (xaflags & XAResource.TMONEPHASE) != 0;
281: try {
282: xaResource.commit(xid, isOnePhase);
283: if (SanityManager.DEBUG)
284: connThread.trace("committed XA transaction: xaRetVal="
285: + xaRetVal);
286:
287: } catch (XAException xe) {
288: xaRetVal = processXAException(xe);
289: }
290: writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, xaRetVal, null);
291:
292: }
293:
294: /**
295: * Rollback transaction
296: * @param xid Xid for rollback for global transaction.
297: * If xid formatid is -1 it represents a local transaction
298: */
299: private void rollbackTransaction(Xid xid)
300: throws DRDAProtocolException {
301: boolean local = (xid.getFormatId() == -1);
302: if (local)
303: rollbackLocalTransaction();
304: else
305: rollbackXATransaction(xid);
306: }
307:
308: /**
309: * Rollback a local transaction
310: *
311: */
312: private void rollbackLocalTransaction()
313: throws DRDAProtocolException {
314: int xaRetVal = XAResource.XA_OK;
315: try {
316: connThread.getDatabase().rollback();
317: } catch (Exception e) {
318: xaRetVal = XAException.XAER_RMFAIL;
319: if (SanityManager.DEBUG) {
320: connThread.getServer().consoleExceptionPrint(e);
321: }
322:
323: }
324: writeSYNCCRD(CodePoint.SYNCTYPE_COMMITTED, xaRetVal, null);
325:
326: }
327:
328: /**
329: * Rollback the xa transaction. Send SYNCCRD response.
330: *
331: * @param xid - XID
332: * @throws DRDAProtocolException
333: */
334: private void rollbackXATransaction(Xid xid)
335: throws DRDAProtocolException {
336: XAResource xaResource = getXAResource();
337: int xaRetVal = xaResource.XA_OK;
338:
339: try {
340: xaResource.rollback(xid);
341: if (SanityManager.DEBUG) {
342: connThread.trace("rollback XA transaction: xaRetVal="
343: + xaRetVal);
344: }
345: } catch (XAException xe) {
346: xaRetVal = processXAException(xe);
347: }
348: writeSYNCCRD(CodePoint.SYNCTYPE_ROLLBACK, xaRetVal, null);
349:
350: }
351:
352: /**
353: * End the xa transaction. Send SYNCRRD response
354: *
355: * @param xid - XID
356: * @param xaflags - xaflags
357: * @throws DRDAProtocolException
358: */
359: private void endXA(Xid xid, int xaflags)
360: throws DRDAProtocolException {
361: XAResource xaResource = getXAResource();
362: int xaRetVal = xaResource.XA_OK;
363:
364: try {
365: xaResource.end(xid, xaflags);
366: if (SanityManager.DEBUG) {
367: connThread.trace("ended XA transaction. xid = " + xid
368: + " xaflags =" + xaflags + "xaRetVal="
369: + xaRetVal);
370: }
371: } catch (XAException xe) {
372: xaRetVal = processXAException(xe);
373: }
374: writeSYNCCRD(CodePoint.SYNCTYPE_END_UOW, xaRetVal, null);
375: }
376:
377: /**
378: * Prepare the xa transaction. Send SYNCCRD response.
379: *
380: * @param xid - XID
381: * @throws DRDAProtocolException
382: */
383: private void prepareXATransaction(Xid xid)
384: throws DRDAProtocolException {
385: XAResource xaResource = getXAResource();
386: int xaRetVal = xaResource.XA_OK;
387:
388: try {
389: xaRetVal = xaResource.prepare(xid);
390: if (SanityManager.DEBUG) {
391: connThread.trace("prepared xa transaction: xaRetVal="
392: + xaRetVal);
393: }
394: } catch (XAException xe) {
395: xaRetVal = processXAException(xe);
396: }
397: writeSYNCCRD(CodePoint.SYNCTYPE_PREPARE, xaRetVal, null);
398: }
399:
400: /**
401: * Forget the xa transaction. Send SYNCCRD response.
402: *
403: * @param xid - XID
404: * @throws DRDAProtocolException
405: */
406: private void forgetXATransaction(Xid xid)
407: throws DRDAProtocolException {
408: XAResource xaResource = getXAResource();
409: int xaRetVal = xaResource.XA_OK;
410:
411: try {
412: xaResource.forget(xid);
413: if (SanityManager.DEBUG) {
414: connThread.trace("forgot xa transaction: xaRetVal="
415: + xaRetVal);
416: }
417: } catch (XAException xe) {
418: xaRetVal = processXAException(xe);
419: }
420: writeSYNCCRD(CodePoint.SYNCTYPE_REQ_FORGET, xaRetVal, null);
421: }
422:
423: // JCC doesn't send xaflags but always wants TMSTARTRSCAN.
424: //So default to that if we got no xaflags
425: private void recoverXA() throws DRDAProtocolException {
426: recoverXA(XAResource.TMSTARTRSCAN);
427: }
428:
429: /**
430: * Call recover. Send SYNCCRD response with indoubt list
431: *
432: * @throws DRDAProtocolException
433: */
434: private void recoverXA(int xaflags) throws DRDAProtocolException {
435: XAResource xaResource = getXAResource();
436: int xaRetVal = xaResource.XA_OK;
437: Xid[] indoubtXids = null;
438: try {
439: indoubtXids = xaResource.recover(xaflags);
440: } catch (XAException xe) {
441: xaRetVal = processXAException(xe);
442: }
443: writeSYNCCRD(CodePoint.SYNCTYPE_INDOUBT, xaRetVal, indoubtXids);
444: }
445:
446: /** Write SYNCCRD (SYNCCTL response)
447: * @param synctype - XA Command to send response for see parseSYNCTYPE
448: * @param xaRetVal - return value from XA command
449: * @param xids - list of xids to return for recover.
450: * null for other commands
451: * @throws DRDAProtocolException
452: */
453: private void writeSYNCCRD(int synctype, int xaRetVal, Xid[] xids)
454: throws DRDAProtocolException {
455: writer.createDssReply();
456: writer.startDdm(CodePoint.SYNCCRD);
457: writer.startDdm(CodePoint.XARETVAL);
458: writer.writeInt(xaRetVal);
459: writer.endDdm();
460: if (xids != null)
461: writePRPHRCLST(xids);
462: writer.endDdmAndDss();
463: }
464:
465: /** write PRPHRCLST (indoubt list)
466: *
467: * @param xids - list of indoubt xa transactions obtained from recover
468: * @throws DRDAProtocolException
469: */
470: private void writePRPHRCLST(Xid[] xids)
471: throws DRDAProtocolException {
472: int xidcnt = (xids == null ? 0 : xids.length);
473: writer.startDdm(CodePoint.PRPHRCLST);
474: writer.writeScalar2Bytes(CodePoint.XIDCNT, xidcnt);
475: for (int i = 0; i < xidcnt; i++)
476: writeXID(xids[i]);
477: writer.endDdm();
478: }
479:
480: /** write XID
481: *
482: * @param xid - XID to write
483: * @throws DRDAProtocolException
484: */
485:
486: private void writeXID(Xid xid) throws DRDAProtocolException {
487: writer.startDdm(CodePoint.XID);
488: int formatId = xid.getFormatId();
489: byte[] gtrid = xid.getGlobalTransactionId();
490: byte[] bqual = xid.getBranchQualifier();
491:
492: writer.writeInt(formatId);
493: writer.writeInt(gtrid.length);
494: writer.writeInt(bqual.length);
495: writer.writeBytes(gtrid);
496: writer.writeBytes(bqual);
497: writer.endDdm();
498: }
499:
500: /** get XAResource for the connection
501: *
502: * @return XAResource
503: */
504: private XAResource getXAResource() {
505: return ((XADatabase) connThread.getDatabase()).getXAResource();
506:
507: }
508:
509: /** printable syncType for debug output
510: * @param syncType
511: * @return - sync type meaning
512: */
513: private String syncTypeToString(int syncType) {
514: switch (syncType) {
515: case CodePoint.SYNCTYPE_NEW_UOW:
516: return "SYNCTYPE_NEW_UOW";
517:
518: case CodePoint.SYNCTYPE_END_UOW:
519: return "SYNCTYPE_END_UOW";
520:
521: case CodePoint.SYNCTYPE_PREPARE:
522: return "SYNCTYPE_PREPARE";
523:
524: case CodePoint.SYNCTYPE_MIGRATE:
525: return "SYNCTYPE_MIGRATE";
526:
527: case CodePoint.SYNCTYPE_REQ_COMMIT:
528: return "SYNCTYPE_REQ_COMMIT";
529:
530: case CodePoint.SYNCTYPE_COMMITTED:
531: return "SYNCTYPE_COMMITTED";
532:
533: case CodePoint.SYNCTYPE_REQ_FORGET:
534: return "SYNCTYPE_FORGET";
535:
536: case CodePoint.SYNCTYPE_ROLLBACK:
537: return "SYNCTYPE_ROLLBACK";
538:
539: case CodePoint.SYNCTYPE_REQ_LOG:
540: return "SYNCTYPE_REQ_LOG";
541:
542: case CodePoint.SYNCTYPE_MIGRATED:
543: return "SYNCTYPE_MIGRATED";
544:
545: case CodePoint.SYNCTYPE_INDOUBT:
546: return "SYNCTYPE_INDOUBT";
547:
548: default:
549: return "UNKNOWN SYNCTYPE";
550: }
551: }
552:
553: /**
554: * printable xaflags
555: * @param xaflags
556: * @return printable xaflags for debug output
557: */
558: private String xaflagsToString(int xaflags) {
559: switch (xaflags) {
560: case XAResource.TMENDRSCAN:
561: return "XAResource.TMENDRSCAN";
562:
563: case XAResource.TMFAIL:
564: return "XAResource.TMFAIL";
565:
566: case XAResource.TMNOFLAGS:
567: return "XAResource.TMNOFLAGS";
568:
569: case XAResource.TMJOIN:
570: return "XAResource.TMJOIN";
571:
572: case XAResource.TMONEPHASE:
573: return "XAResource.TMONEPHASE";
574:
575: case XAResource.TMRESUME:
576: return "XAResource.TMRESUME";
577:
578: case XAResource.TMSTARTRSCAN:
579: return "XAResource.TMSTARTRSCAN";
580:
581: case XAResource.TMSUCCESS:
582: return "XAResource.TMSUCCESS";
583:
584: case XAResource.TMSUSPEND:
585: return "XAResource.TMSUSPEND";
586:
587: default:
588: return "UNRECOGNIZED flags:" + xaflags;
589:
590: }
591: }
592:
593: /**
594: * return xa exception errorCode.
595: * print to console for debug output.
596: * @param xe - XA Exception
597: */
598: private int processXAException(XAException xe) {
599: int xaRetVal = xe.errorCode;
600: if (SanityManager.DEBUG) {
601: connThread.getServer().consoleExceptionPrint(xe);
602: }
603: return xaRetVal;
604: }
605:
606: }
|