001: /*
002: * @(#) TransactionRecoveryImpl.java
003: *
004: * JOTM: Java Open Transaction Manager
005: *
006: *
007: * This module was originally developed by
008: *
009: * - Bull S.A. as part of the JOnAS application server code released in
010: * July 1999 (www.bull.com)
011: *
012: * --------------------------------------------------------------------------
013: * The original code and portions created by Bull SA are
014: * Copyright (c) 1999 BULL SA
015: * All rights reserved.
016: *
017: * Redistribution and use in source and binary forms, with or without
018: * modification, are permitted provided that the following conditions are met:
019: *
020: * -Redistributions of source code must retain the above copyright notice, this
021: * list of conditions and the following disclaimer.
022: *
023: * -Redistributions in binary form must reproduce the above copyright notice,
024: * this list of conditions and the following disclaimer in the documentation
025: * and/or other materials provided with the distribution.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: * --------------------------------------------------------------------------
040: * $Id: TransactionRecoveryImpl.java,v 1.6 2005/04/21 22:51:49 tonyortiz Exp $
041: * --------------------------------------------------------------------------
042: */
043:
044: package org.objectweb.jotm;
045:
046: import java.io.IOException;
047: import java.io.FileInputStream;
048: import java.nio.ByteBuffer;
049: import java.util.Collections;
050: import java.util.HashMap;
051: import java.util.Map;
052: import java.util.Properties;
053: import java.util.Vector;
054:
055: import javax.transaction.SystemException;
056: import javax.transaction.xa.XAResource;
057:
058: import org.objectweb.howl.log.Configuration;
059: import org.objectweb.howl.log.LogConfigurationException;
060: import org.objectweb.howl.log.LogException;
061: import org.objectweb.howl.log.LogRecord;
062: import org.objectweb.howl.log.LogRecordType;
063: import org.objectweb.howl.log.ReplayListener;
064: import org.objectweb.howl.log.xa.XACommittingTx;
065: import org.objectweb.howl.log.xa.XALogRecord;
066: import org.objectweb.howl.log.xa.XALogger;
067:
068: import javax.transaction.xa.XAException;
069:
070: /**
071: *
072: * @author Tony Ortiz
073: */
074:
075: public class TransactionRecoveryImpl implements TransactionRecovery {
076:
077: private transient static TransactionRecoveryImpl unique = null;
078:
079: // Static hashtable: Resource Manager Name ---> Connection
080: private transient static Map nameResourceManager = Collections
081: .synchronizedMap(new HashMap());
082:
083: // Static hashtable: XA Resource Name ---> XAResource
084: private transient static Map nameXAResource = Collections
085: .synchronizedMap(new HashMap());
086:
087: // Jotm Recovery
088: private transient static JotmRecovery tmrecovery = null;
089: //private transient static boolean dorecovery = false;
090: private transient static boolean startrecoverycalled = false;
091:
092: // XALogger info
093: private transient static XALogger xaLog = null;
094: private transient static XACommittingTx rmCommitTx = null;
095:
096: // Vector used to hold all registered Resource Managers
097: // until they can be written to the Howl Logger.
098: private transient static Vector vRmRegistration = new Vector();
099: private RmRegistration myrmRegistration = null;
100:
101: /**
102: * -Djotm.base property
103: */
104: private static final String JOTM_BASE = "jotm.base";
105:
106: /**
107: * jonas.base property
108: */
109: private static final String JONAS_BASE = "jonas.base";
110:
111: /**
112: * configuration directory name
113: */
114: private static final String CONFIG_DIR = "conf";
115:
116: /**
117: * System properties
118: */
119: private static Properties systEnv = System.getProperties();
120:
121: /**
122: * JONAS_BASE
123: */
124: private static String jonasBase = systEnv.getProperty(JONAS_BASE);
125:
126: /**
127: * JOTM_BASE
128: */
129: private static String jotmBase = systEnv.getProperty(JOTM_BASE);
130:
131: /**
132: * Separator of file
133: */
134: private static String fileSeparator = systEnv
135: .getProperty("file.separator");
136:
137: /**
138: * Default constructor.
139: */
140:
141: public TransactionRecoveryImpl() throws LogException, IOException,
142: Exception {
143:
144: if (TraceTm.recovery.isDebugEnabled()) {
145: TraceTm.recovery
146: .debug("TransactionRecoveryImpl constructor");
147: }
148:
149: unique = this ;
150:
151: // Check the JONAS_BASE and JOTM_BASE environment properties
152: // If on of them is not found, check the transactionRecovery value
153: // from Current to see if recovery is enabled(true)/disabled(false).
154:
155: String myBase = null;
156:
157: if (jonasBase == null) {
158: if (jotmBase == null) {
159: if (!Current.getDefaultRecovery()) {
160: if (TraceTm.recovery.isDebugEnabled()) {
161: TraceTm.recovery
162: .debug("JOTM Recovery is disabled");
163: }
164: return; // transaction recovery is disabled
165: }
166: } else {
167: myBase = jotmBase;
168: }
169: } else {
170: myBase = jonasBase;
171: }
172:
173: myBase = myBase.trim();
174:
175: // JOTM_BASE/conf/fileName
176: String fileFullPathname = myBase + fileSeparator + CONFIG_DIR
177: + fileSeparator + "jotm.properties";
178:
179: if (TraceTm.recovery.isDebugEnabled()) {
180: TraceTm.recovery.debug("JOTM properties file= "
181: + fileFullPathname);
182: }
183:
184: Properties howlprop = new Properties();
185: try {
186: FileInputStream inStr = new FileInputStream(
187: fileFullPathname);
188: systEnv.load(inStr);
189: } catch (Exception e) {
190: Current.setDefaultRecovery(false);
191: return;
192: }
193:
194: if (systEnv.getProperty("jotm.recovery.Enabled").trim()
195: .equalsIgnoreCase("true")) { // recovery is enabled
196: Current.setDefaultRecovery(true);
197: if (TraceTm.recovery.isDebugEnabled()) {
198: TraceTm.recovery.debug("JOTM Recovery is enabled");
199: }
200: } else { // recovery disabled
201: Current.setDefaultRecovery(false);
202: if (TraceTm.recovery.isDebugEnabled()) {
203: TraceTm.recovery.debug("JOTM Recovery is disabled");
204: }
205: return;
206: }
207:
208: String myhowlprop = null;
209: myhowlprop = systEnv.getProperty("howl.log.ListConfiguration",
210: "false");
211: howlprop.put("listConfig", myhowlprop);
212: myhowlprop = systEnv.getProperty("howl.log.BufferSize", "4");
213: howlprop.put("bufferSize", myhowlprop);
214: myhowlprop = systEnv.getProperty("howl.log.MinimumBuffers",
215: "16");
216: howlprop.put("minBuffers", myhowlprop);
217: myhowlprop = systEnv.getProperty("howl.log.MaximumBuffers",
218: "16");
219: howlprop.put("maxBuffers", myhowlprop);
220: myhowlprop = systEnv.getProperty(
221: "howl.log.MaximumBlocksPerFile", "200");
222: howlprop.put("maxBlocksPerFile", myhowlprop);
223: myhowlprop = systEnv.getProperty("howl.log.FileDirectory",
224: systEnv.getProperty("basedir", "."));
225: howlprop.put("logFileDir", myhowlprop);
226: myhowlprop = systEnv.getProperty("howl.log.FileName", "howl");
227: howlprop.put("logFileName", myhowlprop);
228: myhowlprop = systEnv.getProperty("howl.log.MaximumFiles", "2");
229: howlprop.put("maxLogFiles", myhowlprop);
230:
231: try {
232: howlOpenLog(howlprop);
233: } catch (Exception e) {
234: TraceTm.jotm
235: .warn("howlOpenLog: LogException occured in howlOpenLog() "
236: + e.getMessage());
237: Current.setDefaultRecovery(false);
238: TraceTm.recovery.warn("JOTM Recovery is disabled");
239: return;
240: }
241: }
242:
243: /**
244: * Returns the unique instance of the class or <code>null</code> if not
245: * initialized in case of plain client.
246: *
247: * @return The <code>TransactionRecovery</code> object created
248: */
249:
250: public static TransactionRecoveryImpl getTransactionRecovery() {
251:
252: return unique;
253: }
254:
255: public JotmRecovery getJotmRecovery() {
256:
257: return tmrecovery;
258: }
259:
260: public Vector getRmRegistration() {
261:
262: return vRmRegistration;
263: }
264:
265: // ------------------------------------------------------------------
266: // JOTM Recovery Support Methods
267: // ------------------------------------------------------------------
268:
269: /**
270: * Register a Resource Manager with the JOTM Transaction Manager.
271: *
272: * @param rmName The Resource Manager to be registered.
273: */
274:
275: /* added 04/13/05 */
276: public void registerResourceManager(String rmName,
277: XAResource rmXares, String info, Properties rmProperties,
278: TransactionResourceManager trm) throws XAException {
279: if (TraceTm.recovery.isDebugEnabled()) {
280: TraceTm.recovery
281: .debug("Register Resource Manager Properties "
282: + rmName + rmProperties + " to Connection "
283: + rmXares);
284: }
285:
286: this .registerResourceManager(rmName, rmXares, info, trm);
287: }
288:
289: public void registerResourceManager(String rmName,
290: XAResource rmXares, String info,
291: TransactionResourceManager tranrm) throws XAException {
292:
293: if (!(tranrm == null)) { // initial implementation, call back immediately
294: tranrm.returnXAResource(rmName, rmXares);
295: }
296:
297: if (!Current.getDefaultRecovery()) {
298: if (TraceTm.recovery.isDebugEnabled()) {
299: TraceTm.recovery.debug("JOTM Recovery is disabled");
300: }
301: return; // transaction recovery is disabled
302: }
303:
304: // put the Resource Manager/XAResource mapping into the hashtable
305:
306: if (TraceTm.recovery.isDebugEnabled()) {
307: TraceTm.recovery.debug("Register Resource Manager "
308: + rmName + " to Connection " + rmXares);
309: }
310:
311: XAResource xares = null;
312: Object hash_key = new String(rmName);
313:
314: Object myrmXares = (Object) nameResourceManager.get(hash_key);
315:
316: if (myrmXares == null) {
317: nameResourceManager.put(hash_key, rmXares);
318: } else {
319: xares = (XAResource) myrmXares;
320:
321: if (xares.equals(rmXares)) {
322: if (TraceTm.recovery.isDebugEnabled()) {
323: TraceTm.recovery.debug(rmName
324: + " already registered");
325: return;
326: }
327: } else {
328: nameResourceManager.put(hash_key, rmXares);
329: }
330: }
331:
332: myrmRegistration = new RmRegistration();
333: myrmRegistration.rmAddRegistration(rmName, rmXares, rmXares
334: .getClass().getName());
335: vRmRegistration.addElement(myrmRegistration);
336:
337: // if startResourceManagerRecovery has been called before
338: // (e.g. during Jonas startup)it must be called when a
339: // Resource Manager registered
340:
341: if (startrecoverycalled) {
342: try {
343: startResourceManagerRecovery();
344: } catch (XAException e) {
345: throw new XAException(
346: "startResourceManagerRecovery failed"
347: + e.getMessage());
348: }
349: }
350:
351: }
352:
353: /**
354: * Provide information regarding the status and state of the XAResource.
355: *
356: * @param rmName The Resource Manager to be reported upon.
357: *
358: * @return XAResource The XAResource assigned to the Resource Managere.
359: */
360:
361: public XAResource reportResourceManager(String rmName)
362: throws XAException {
363:
364: if (!Current.getDefaultRecovery()) {
365: if (TraceTm.recovery.isDebugEnabled()) {
366: TraceTm.recovery.debug("JOTM Recovery is disabled");
367: }
368: return null; // transaction recovery is disabled
369: }
370:
371: // given the name, get the corresponding Connection from the hashtable.
372:
373: if (TraceTm.recovery.isDebugEnabled()) {
374: TraceTm.recovery
375: .debug("get Connection from Resource Manager "
376: + rmName);
377: }
378:
379: Object hash_key = new String(rmName);
380: XAResource myXares = (XAResource) nameResourceManager
381: .get(hash_key);
382:
383: if (myXares == null) {
384: throw new XAException("Named Resource Manager " + rmName
385: + " does not exist");
386: }
387:
388: return myXares;
389: }
390:
391: /**
392: * Unregister a Resource Manager from the JOTM Transaction Manager.
393: *
394: * @param rmName The Resource Manager to be unregistered.
395: */
396:
397: public void unregisterResourceManager(String rmName,
398: XAResource rmXares) throws XAException {
399:
400: if (!Current.getDefaultRecovery()) {
401: if (TraceTm.recovery.isDebugEnabled()) {
402: TraceTm.recovery.debug("JOTM Recovery is disabled");
403: }
404: return; // transaction recovery is disabled
405: }
406:
407: // Unregister the Resource Manager from the name (hash table).
408:
409: if (TraceTm.recovery.isDebugEnabled()) {
410: TraceTm.recovery.debug("Remove Resource Manager " + rmName
411: + " from Connection " + rmXares);
412: }
413:
414: Object hash_key = new String(rmName);
415: XAResource myrmXares = (XAResource) nameResourceManager
416: .get(hash_key);
417:
418: if (myrmXares.equals(rmXares)) {
419: nameResourceManager.remove(hash_key);
420: } else {
421: throw new XAException("Resource Manager " + rmName
422: + " not associated to " + rmXares);
423: }
424: }
425:
426: /**
427: * Log (in Howl) every Resource Manager (XAResource) that has been
428: * registered.
429: *
430: * @exception XAException Thrown if the transaction manager
431: * encounters an unexpected error condition
432: */
433:
434: public void startResourceManagerRecovery() throws XAException {
435:
436: if (!Current.getDefaultRecovery()) {
437: if (TraceTm.recovery.isDebugEnabled()) {
438: TraceTm.recovery.debug("JOTM Recovery is disabled");
439: }
440: return; // transaction recovery is disabled
441: }
442:
443: int rmcount = vRmRegistration.size();
444: if (TraceTm.recovery.isDebugEnabled()) {
445: TraceTm.recovery.debug("LogResourceManager count= "
446: + rmcount);
447: }
448:
449: if (rmcount == 0)
450: return;
451:
452: XACommittingTx myrmCommitTx = null;
453:
454: byte[][] rmBuffer = new byte[rmcount + 1][];
455:
456: byte[] rmRecord1 = null;
457: byte[] rmRecord2 = null;
458:
459: String resm1 = "RM1";
460: String resm2 = "RM2";
461:
462: long rmdate = System.currentTimeMillis();
463:
464: rmRecord1 = new byte[3 + 8 + 4];
465:
466: ByteBuffer rm1 = ByteBuffer.wrap(rmRecord1);
467: rm1.put(resm1.getBytes());
468: rm1.putLong(rmdate);
469: rm1.putInt(rmcount);
470:
471: rmBuffer[0] = rm1.array();
472:
473: for (int i = 0; i < rmcount; i++) {
474: myrmRegistration = (RmRegistration) vRmRegistration
475: .elementAt(i);
476: String rmName = myrmRegistration.rmGetName();
477: XAResource xaRes = myrmRegistration.rmGetXaRes();
478: String xaresName = myrmRegistration.rmGetXaResName();
479:
480: if (TraceTm.recovery.isDebugEnabled()) {
481: TraceTm.recovery.debug("LogResourceManager rmName= "
482: + rmName);
483: TraceTm.recovery.debug(" xaRes= " + xaresName);
484: TraceTm.recovery.debug(" rmIndex= " + i);
485: }
486:
487: int rmlength = rmName.length();
488: int xaReslength = xaRes.toString().length();
489: int xaResNamelength = xaresName.length();
490:
491: if (TraceTm.recovery.isDebugEnabled()) {
492: TraceTm.recovery.debug("rm length=" + rmlength);
493: TraceTm.recovery.debug("xaRes length= " + xaReslength);
494: }
495:
496: rmRecord2 = new byte[3 + 4 + rmlength + 4 + xaReslength + 4
497: + xaResNamelength + 4];
498: ByteBuffer rm2 = ByteBuffer.wrap(rmRecord2);
499:
500: rm2.put(resm2.getBytes());
501: rm2.putInt(rmlength);
502: rm2.put(rmName.getBytes());
503: rm2.putInt(xaReslength);
504: rm2.put(xaRes.toString().getBytes());
505: rm2.putInt(xaResNamelength);
506: rm2.put(xaresName.getBytes());
507: rm2.putInt(i);
508:
509: rmBuffer[i + 1] = rm2.array(); // First record (0) is always rm1
510: }
511:
512: try {
513: myrmCommitTx = howlCommitLog(rmBuffer);
514: } catch (Exception e) {
515: // If we cannot write the Log, we cannot perform recovery
516:
517: String howlerror = "Cannot howlCommitLog:" + e + " --"
518: + e.getMessage();
519: TraceTm.jotm.error("Got LogException from howlCommitLog: "
520: + howlerror);
521: rmCommitTx = null;
522:
523: throw new XAException(howlerror);
524: }
525:
526: if (!(rmCommitTx == null)) {
527: byte[] rmDone = new byte[11];
528: byte[][] rmDoneRecord = new byte[1][11];
529:
530: rmDone = "RM3JOTMDONE".getBytes();
531:
532: try {
533: rmDoneRecord[0] = rmDone;
534: howlDoneLog(rmDoneRecord, rmCommitTx);
535: } catch (Exception f) {
536: String howlerror = "Cannot howlDoneLog:" + f + "--"
537: + f.getMessage();
538: TraceTm.jotm
539: .error("Got LogException from howlDoneLog: "
540: + howlerror);
541: }
542: }
543:
544: rmCommitTx = myrmCommitTx;
545:
546: try {
547: recoverResourceManager();
548: } catch (XAException e) {
549: throw new XAException("Cannot perform recovery "
550: + e.getMessage());
551: }
552:
553: startrecoverycalled = true;
554: }
555:
556: /**
557: * Recover a Resource Manager with the JOTM Transaction Manager.
558: *
559: * @exception XAException Thrown if the transaction manager
560: * encounters an unexpected error condition
561: */
562:
563: public void recoverResourceManager() throws XAException {
564:
565: if (!Current.getDefaultRecovery()) {
566: if (TraceTm.recovery.isDebugEnabled()) {
567: TraceTm.recovery.debug("JOTM Recovery is disabled");
568: }
569: return; // transaction recovery is disabled
570: }
571:
572: if (TraceTm.recovery.isDebugEnabled()) {
573: TraceTm.recovery.debug("recoverResourceManager");
574: }
575:
576: if (vRmRegistration.size() == 0) {
577: if (TraceTm.recovery.isDebugEnabled()) {
578: TraceTm.recovery.debug("Nothing to recover");
579: }
580: return;
581: }
582:
583: // If incomplete commit records were found in Howl, we may need to
584: // recover transactions (xids).
585:
586: try {
587: tmrecovery.recoverTransactions(vRmRegistration);
588: } catch (XAException e) {
589: throw new XAException("Unable to recover transactions"
590: + e.getMessage());
591: }
592: }
593:
594: /* HOWL Support Methods */
595:
596: private class xaReplayListener implements ReplayListener {
597:
598: public void onRecord(LogRecord lr) {
599:
600: if (TraceTm.recovery.isDebugEnabled()) {
601: TraceTm.recovery.debug("LogRecord type= " + lr.type);
602: }
603:
604: switch (lr.type) {
605: case LogRecordType.EOB:
606: if (TraceTm.recovery.isDebugEnabled()) {
607: TraceTm.recovery.debug("Howl End of Buffer Record");
608: }
609: break;
610: case LogRecordType.END_OF_LOG:
611: if (TraceTm.recovery.isDebugEnabled()) {
612: TraceTm.recovery.debug("Howl End of Log Record");
613: }
614: break;
615: case LogRecordType.XACOMMIT:
616: if (TraceTm.recovery.isDebugEnabled()) {
617: TraceTm.recovery.debug("Howl XA Commit Record");
618: }
619: tmrecovery.rebuildTransaction((XALogRecord) lr);
620: break;
621: case LogRecordType.XADONE:
622: if (TraceTm.recovery.isDebugEnabled()) {
623: TraceTm.recovery.debug("Howl XA Done Record");
624: }
625: break;
626: case LogRecordType.USER:
627: if (TraceTm.recovery.isDebugEnabled()) {
628: TraceTm.recovery.debug("Howl User Record");
629: }
630: break;
631: default:
632: if (TraceTm.recovery.isDebugEnabled()) {
633: TraceTm.recovery.debug("Unknown Howl LogRecord");
634: }
635: break;
636: }
637: }
638:
639: public void onError(LogException exception) {
640: // TODO Auto-generated method stub
641: if (TraceTm.recovery.isDebugEnabled()) {
642: TraceTm.recovery.debug("onError");
643: }
644: }
645:
646: public LogRecord getLogRecord() {
647: if (TraceTm.recovery.isDebugEnabled()) {
648: TraceTm.recovery.debug("getLogRecord");
649: }
650: return new XALogRecord(120);
651: }
652: }
653:
654: /**
655: * open the Howl Log
656: */
657:
658: synchronized void howlOpenLog(Properties phowlprop)
659: throws SystemException {
660:
661: if (!(xaLog == null)) {
662: if (TraceTm.recovery.isDebugEnabled()) {
663: TraceTm.recovery.debug("Howl Log already opened");
664: }
665: return;
666: }
667:
668: if (TraceTm.recovery.isDebugEnabled()) {
669: TraceTm.recovery.debug("Open howl log");
670: }
671:
672: try {
673: Configuration cfg = new Configuration(phowlprop);
674: xaLog = new XALogger(cfg);
675: } catch (LogConfigurationException e) {
676: TraceTm.jotm.error("XALogger: LogConfigurationException");
677: throw new SystemException(
678: "LogConfigurationException occured in XALogger() "
679: + e.getMessage());
680: } catch (IOException e) {
681: TraceTm.jotm.error("XALogger: IOException");
682: throw new SystemException(
683: "IOException occured in XALogger() "
684: + e.getMessage());
685: } catch (Exception e) {
686: TraceTm.jotm.error("XALogger: Exception");
687: throw new SystemException(
688: "Exeception occurred in XALogger() "
689: + e.getMessage());
690: }
691:
692: tmrecovery = new JotmRecovery();
693:
694: xaReplayListener myxarl = new xaReplayListener();
695:
696: if (TraceTm.recovery.isDebugEnabled()) {
697: TraceTm.recovery.debug("xaLog.open");
698: }
699:
700: try {
701: xaLog.open(null);
702: } catch (LogException e) {
703: TraceTm.jotm.error("xaLog.open: LogException");
704: throw new SystemException(
705: "LogException occured in xaLog.open() "
706: + e.getMessage());
707: } catch (IOException e) {
708: TraceTm.jotm.error("xaLog.open: IOException");
709: throw new SystemException(
710: "IOException occured in xaLog.open() "
711: + e.getMessage());
712: } catch (InterruptedException e) {
713: TraceTm.jotm.error("xaLog.open: InterruptedException");
714: throw new SystemException(
715: "InterruptedException occured in xaLog.open() "
716: + e.getMessage());
717: } catch (ClassNotFoundException e) {
718: TraceTm.jotm.error("xaLog.open: ClassNotFoundException");
719: throw new SystemException(
720: "ClassNotFoundException occured in xaLog.open() "
721: + e.getMessage());
722: } catch (Exception e) {
723: TraceTm.jotm.error("xaLog.open: Exception "
724: + e.getMessage());
725: throw new SystemException(
726: "Exception occurred in xaLog.open() "
727: + e.getMessage());
728: }
729:
730: xaLog.replayActiveTx(myxarl);
731: }
732:
733: /**
734: * write the Done record to the Howl Log
735: */
736:
737: void howlCloseLog() throws SystemException {
738:
739: if (TraceTm.recovery.isDebugEnabled()) {
740: TraceTm.recovery.debug("Close howl log");
741: }
742:
743: if (xaLog == null)
744: return;
745:
746: try {
747: xaLog.close();
748: } catch (IOException e) {
749: TraceTm.jotm.error("xaLog.close: IOException");
750: throw new SystemException(
751: "IOException occured in xaLog.close() "
752: + e.getMessage());
753: } catch (InterruptedException e) {
754: TraceTm.jotm.error("xaLog.close: InterruptedException");
755: throw new SystemException(
756: "InterruptedException occured in xaLog.close() "
757: + e.getMessage());
758: }
759:
760: xaLog = null;
761:
762: if (TraceTm.recovery.isDebugEnabled()) {
763: TraceTm.recovery.debug("Howl log closed");
764: }
765: }
766:
767: /**
768: * write the Commit record to the Howl Log
769: */
770:
771: public XACommittingTx howlCommitLog(byte[][] xaCmRec)
772: throws LogException, Exception {
773: if (TraceTm.recovery.isDebugEnabled()) {
774: TraceTm.recovery.debug("Commit howl log");
775: }
776: return xaLog.putCommit(xaCmRec);
777: }
778:
779: /**
780: * write the Done record to the Howl Log
781: */
782:
783: public void howlDoneLog(byte[][] xaDnRec, XACommittingTx xaCmTx)
784: throws LogException, Exception {
785: if (TraceTm.recovery.isDebugEnabled()) {
786: TraceTm.recovery.debug("Done howl log");
787: }
788: xaLog.putDone(xaDnRec, xaCmTx);
789: }
790:
791: /**
792: * close Transaction Recovery Log
793: */
794:
795: public void forget() throws LogException, Exception {
796:
797: if (!Current.getDefaultRecovery()) {
798: if (TraceTm.recovery.isDebugEnabled()) {
799: TraceTm.recovery.debug("JOTM Recovery is disabled");
800: }
801: } else {
802: howlCloseLog();
803: }
804:
805: }
806:
807: }
|