1 43 44 package org.objectweb.jotm; 45 46 import java.io.IOException ; 47 import java.io.FileInputStream ; 48 import java.nio.ByteBuffer ; 49 import java.util.Collections ; 50 import java.util.HashMap ; 51 import java.util.Map ; 52 import java.util.Properties ; 53 import java.util.Vector ; 54 55 import javax.transaction.SystemException ; 56 import javax.transaction.xa.XAResource ; 57 58 import org.objectweb.howl.log.Configuration; 59 import org.objectweb.howl.log.LogConfigurationException; 60 import org.objectweb.howl.log.LogException; 61 import org.objectweb.howl.log.LogRecord; 62 import org.objectweb.howl.log.LogRecordType; 63 import org.objectweb.howl.log.ReplayListener; 64 import org.objectweb.howl.log.xa.XACommittingTx; 65 import org.objectweb.howl.log.xa.XALogRecord; 66 import org.objectweb.howl.log.xa.XALogger; 67 68 import javax.transaction.xa.XAException ; 69 70 74 75 public class TransactionRecoveryImpl implements TransactionRecovery { 76 77 private transient static TransactionRecoveryImpl unique = null; 78 79 private transient static Map nameResourceManager = Collections.synchronizedMap(new HashMap ()); 81 82 private transient static Map nameXAResource = Collections.synchronizedMap(new HashMap ()); 84 85 private transient static JotmRecovery tmrecovery = null; 87 private transient static boolean startrecoverycalled = false; 89 90 private transient static XALogger xaLog = null; 92 private transient static XACommittingTx rmCommitTx = null; 93 94 private transient static Vector vRmRegistration = new Vector (); 97 private RmRegistration myrmRegistration = null; 98 99 102 private static final String JOTM_BASE = "jotm.base"; 103 104 107 private static final String JONAS_BASE = "jonas.base"; 108 109 112 private static final String CONFIG_DIR = "conf"; 113 114 117 private static Properties systEnv = System.getProperties(); 118 119 122 private static String jonasBase = systEnv.getProperty(JONAS_BASE); 123 124 127 private static String jotmBase = systEnv.getProperty(JOTM_BASE); 128 129 132 private static String fileSeparator = systEnv.getProperty("file.separator"); 133 134 137 138 public TransactionRecoveryImpl() throws LogException, IOException , Exception { 139 140 if (TraceTm.recovery.isDebugEnabled()) { 141 TraceTm.recovery.debug("TransactionRecoveryImpl constructor"); 142 } 143 144 unique = this; 145 146 150 String myBase=null; 151 152 if (jonasBase == null) { 153 if (jotmBase == null) { 154 if (!Current.getDefaultRecovery()) { 155 if (TraceTm.recovery.isDebugEnabled()) { 156 TraceTm.recovery.debug("JOTM Recovery is disabled"); 157 } 158 return; } 160 } else { 161 myBase = jotmBase; 162 } 163 } else { 164 myBase = jonasBase; 165 } 166 167 myBase = myBase.trim(); 168 169 String fileFullPathname = myBase + fileSeparator + CONFIG_DIR + fileSeparator + "jotm.properties"; 171 172 if (TraceTm.recovery.isDebugEnabled()) { 173 TraceTm.recovery.debug("JOTM properties file= " + fileFullPathname); 174 } 175 176 Properties howlprop = new Properties (); 177 try { 178 FileInputStream inStr = new FileInputStream (fileFullPathname); 179 systEnv.load(inStr); 180 } catch (Exception e){ 181 Current.setDefaultRecovery(false); 182 return; 183 } 184 185 if (systEnv.getProperty("jotm.recovery.Enabled").trim().equalsIgnoreCase("true")) { Current.setDefaultRecovery(true); 187 if (TraceTm.recovery.isDebugEnabled()) { 188 TraceTm.recovery.debug("JOTM Recovery is enabled"); 189 } 190 } else { Current.setDefaultRecovery(false); 192 if (TraceTm.recovery.isDebugEnabled()) { 193 TraceTm.recovery.debug("JOTM Recovery is disabled"); 194 } 195 return; 196 } 197 198 String myhowlprop = null; 199 myhowlprop = systEnv.getProperty ("howl.log.ListConfiguration", "false"); 200 howlprop.put("listConfig", myhowlprop); 201 myhowlprop = systEnv.getProperty ("howl.log.BufferSize", "4"); 202 howlprop.put("bufferSize", myhowlprop); 203 myhowlprop = systEnv.getProperty ("howl.log.MinimumBuffers", "16"); 204 howlprop.put("minBuffers", myhowlprop); 205 myhowlprop = systEnv.getProperty ("howl.log.MaximumBuffers", "16"); 206 howlprop.put("maxBuffers", myhowlprop); 207 myhowlprop = systEnv.getProperty ("howl.log.MaximumBlocksPerFile", "200"); 208 howlprop.put("maxBlocksPerFile", myhowlprop); 209 myhowlprop = systEnv.getProperty ("howl.log.FileDirectory", systEnv.getProperty ("basedir", ".")); 210 howlprop.put("logFileDir", myhowlprop); 211 myhowlprop = systEnv.getProperty ("howl.log.FileName", "howl"); 212 howlprop.put("logFileName", myhowlprop); 213 myhowlprop = systEnv.getProperty ("howl.log.MaximumFiles", "2"); 214 howlprop.put("maxLogFiles", myhowlprop); 215 216 try { 217 howlOpenLog (howlprop); 218 } catch (Exception e) { 219 TraceTm.jotm.warn("howlOpenLog: LogException occured in howlOpenLog() " + e.getMessage()); 220 Current.setDefaultRecovery(false); 221 TraceTm.recovery.warn("JOTM Recovery is disabled"); 222 return; 223 } 224 } 225 226 232 233 public static TransactionRecoveryImpl getTransactionRecovery() { 234 235 return unique; 236 } 237 238 public JotmRecovery getJotmRecovery() { 239 240 return tmrecovery; 241 } 242 243 public Vector getRmRegistration() { 244 245 return vRmRegistration; 246 } 247 251 256 257 258 public void registerResourceManager (String rmName, XAResource rmXares, String info, 259 Properties rmProperties, 260 TransactionResourceManager trm) throws XAException { 261 if ( TraceTm.recovery.isDebugEnabled() ) { 262 TraceTm.recovery.debug("Register Resource Manager Properties " + rmName + rmProperties + " to Connection " + rmXares); 263 } 264 265 this.registerResourceManager (rmName, rmXares, info, trm); 266 } 267 268 public void registerResourceManager (String rmName, XAResource rmXares, String info, 269 TransactionResourceManager tranrm) throws XAException { 270 271 if (!(tranrm==null)) { tranrm.returnXAResource(rmName, rmXares); 273 } 274 275 if (!Current.getDefaultRecovery()) { 276 if (TraceTm.recovery.isDebugEnabled()) { 277 TraceTm.recovery.debug("JOTM Recovery is disabled"); 278 } 279 return; } 281 282 284 if ( TraceTm.recovery.isDebugEnabled() ) { 285 TraceTm.recovery.debug("Register Resource Manager " + rmName + " to Connection " + rmXares); 286 } 287 288 XAResource xares = null; 289 Object hash_key = new String (rmName); 290 291 Object myrmXares = (Object ) nameResourceManager.get(hash_key); 292 293 if (myrmXares == null) { 294 nameResourceManager.put(hash_key, rmXares); 295 } 296 else { 297 xares = (XAResource ) myrmXares; 298 299 if (xares.equals(rmXares)) { 300 if( TraceTm.recovery.isDebugEnabled() ) { 301 TraceTm.recovery.debug(rmName + " already registered"); 302 return; 303 } 304 } 305 else { 306 nameResourceManager.put(hash_key, rmXares); 307 } 308 } 309 310 myrmRegistration = new RmRegistration(); 311 myrmRegistration.rmAddRegistration (rmName, rmXares, rmXares.getClass().getName()); 312 vRmRegistration.addElement(myrmRegistration); 313 314 318 if (startrecoverycalled) { 319 try { 320 startResourceManagerRecovery (); 321 } catch (XAException e) { 322 throw new XAException ("startResourceManagerRecovery failed" + e.getMessage()); 323 } 324 } 325 326 } 327 328 335 336 public XAResource reportResourceManager (String rmName) throws XAException { 337 338 if (!Current.getDefaultRecovery()) { 339 if (TraceTm.recovery.isDebugEnabled()) { 340 TraceTm.recovery.debug("JOTM Recovery is disabled"); 341 } 342 return null; } 344 345 347 if( TraceTm.recovery.isDebugEnabled() ) { 348 TraceTm.recovery.debug("get Connection from Resource Manager " + rmName); 349 } 350 351 Object hash_key = new String (rmName); 352 XAResource myXares = (XAResource ) nameResourceManager.get(hash_key); 353 354 if (myXares == null) { 355 throw new XAException ("Named Resource Manager " + rmName + " does not exist"); 356 } 357 358 return myXares; 359 } 360 361 366 367 public void unregisterResourceManager(String rmName, XAResource rmXares) throws XAException { 368 369 if (!Current.getDefaultRecovery()) { 370 if (TraceTm.recovery.isDebugEnabled()) { 371 TraceTm.recovery.debug("JOTM Recovery is disabled"); 372 } 373 return; } 375 376 378 if ( TraceTm.recovery.isDebugEnabled() ) { 379 TraceTm.recovery.debug("Remove Resource Manager " + rmName + " from Connection " + rmXares); 380 } 381 382 Object hash_key = new String (rmName); 383 XAResource myrmXares = (XAResource ) nameResourceManager.get(hash_key); 384 385 if (myrmXares.equals(rmXares)) { 386 nameResourceManager.remove(hash_key); 387 } 388 else { 389 throw new XAException ("Resource Manager " + rmName + " not associated to " + rmXares); 390 } 391 } 392 393 400 401 public void startResourceManagerRecovery () throws XAException { 402 403 if (!Current.getDefaultRecovery()) { 404 if (TraceTm.recovery.isDebugEnabled()) { 405 TraceTm.recovery.debug("JOTM Recovery is disabled"); 406 } 407 return; } 409 410 int rmcount = vRmRegistration.size(); 411 if (TraceTm.recovery.isDebugEnabled()) { 412 TraceTm.recovery.debug("LogResourceManager count= " +rmcount); 413 } 414 415 if (rmcount == 0) return; 416 417 XACommittingTx myrmCommitTx = null; 418 419 byte [] [] rmBuffer = new byte [rmcount + 1] []; 420 421 byte [] rmRecord1 = null; 422 byte [] rmRecord2 = null; 423 424 String resm1 = "RM1"; 425 String resm2 = "RM2"; 426 427 long rmdate = System.currentTimeMillis(); 428 429 rmRecord1 = new byte[3+8+4]; 430 431 ByteBuffer rm1 = ByteBuffer.wrap(rmRecord1); 432 rm1.put(resm1.getBytes()); 433 rm1.putLong(rmdate); 434 rm1.putInt(rmcount); 435 436 rmBuffer [0] = rm1.array(); 437 438 for (int i = 0; i < rmcount; i++) { 439 myrmRegistration = (RmRegistration)vRmRegistration.elementAt(i); 440 String rmName = myrmRegistration.rmGetName(); 441 XAResource xaRes = myrmRegistration.rmGetXaRes(); 442 String xaresName = myrmRegistration.rmGetXaResName(); 443 444 if (TraceTm.recovery.isDebugEnabled()) { 445 TraceTm.recovery.debug("LogResourceManager rmName= " + rmName); 446 TraceTm.recovery.debug(" xaRes= " + xaresName); 447 TraceTm.recovery.debug(" rmIndex= " + i); 448 } 449 450 int rmlength = rmName.length(); 451 int xaReslength= xaRes.toString().length(); 452 int xaResNamelength = xaresName.length(); 453 454 if (TraceTm.recovery.isDebugEnabled()) { 455 TraceTm.recovery.debug("rm length=" + rmlength); 456 TraceTm.recovery.debug("xaRes length= " + xaReslength); 457 } 458 459 rmRecord2 = new byte[3+4+rmlength+4+xaReslength+4+xaResNamelength+4]; 460 ByteBuffer rm2 = ByteBuffer.wrap(rmRecord2); 461 462 rm2.put(resm2.getBytes()); 463 rm2.putInt(rmlength); 464 rm2.put(rmName.getBytes()); 465 rm2.putInt(xaReslength); 466 rm2.put(xaRes.toString().getBytes()); 467 rm2.putInt(xaResNamelength); 468 rm2.put(xaresName.getBytes()); 469 rm2.putInt(i); 470 471 rmBuffer [i+1] = rm2.array(); } 473 474 try { 475 myrmCommitTx = howlCommitLog(rmBuffer); 476 } catch (Exception e) { 477 479 String howlerror = 480 "Cannot howlCommitLog:" 481 + e 482 + " --" 483 + e.getMessage(); 484 TraceTm.jotm.error("Got LogException from howlCommitLog: "+ howlerror); 485 rmCommitTx = null; 486 487 throw new XAException (howlerror); 488 } 489 490 if (!(rmCommitTx == null)) { 491 byte [] rmDone = new byte [11]; 492 byte [] [] rmDoneRecord = new byte [1] [11]; 493 494 rmDone = "RM3JOTMDONE".getBytes(); 495 496 try { 497 rmDoneRecord [0] = rmDone; 498 howlDoneLog (rmDoneRecord, rmCommitTx); 499 } catch (Exception f) { 500 String howlerror = 501 "Cannot howlDoneLog:" 502 + f 503 + "--" 504 + f.getMessage(); 505 TraceTm.jotm.error("Got LogException from howlDoneLog: "+ howlerror); 506 } 507 } 508 509 rmCommitTx = myrmCommitTx; 510 511 try { 512 recoverResourceManager(); 513 } catch (XAException e) { 514 throw new XAException ("Cannot perform recovery " + e.getMessage()); 515 } 516 517 startrecoverycalled = true; 518 } 519 520 526 527 public void recoverResourceManager () throws XAException { 528 529 if (!Current.getDefaultRecovery()) { 530 if (TraceTm.recovery.isDebugEnabled()) { 531 TraceTm.recovery.debug("JOTM Recovery is disabled"); 532 } 533 return; } 535 536 if ( TraceTm.recovery.isDebugEnabled() ) { 537 TraceTm.recovery.debug("recoverResourceManager"); 538 } 539 540 if (vRmRegistration.size()== 0){ 541 if ( TraceTm.recovery.isDebugEnabled() ) { 542 TraceTm.recovery.debug("Nothing to recover"); 543 } 544 return; 545 } 546 547 550 try { 551 tmrecovery.recoverTransactions(vRmRegistration); 552 } catch (XAException e) { 553 throw new XAException ("Unable to recover transactions" + e.getMessage()); 554 } 555 } 556 557 558 559 private class xaReplayListener implements ReplayListener { 560 561 public void onRecord (LogRecord lr) { 562 563 if (TraceTm.recovery.isDebugEnabled()) { 564 TraceTm.recovery.debug("LogRecord type= " + lr.type); 565 } 566 567 switch(lr.type) { 568 case LogRecordType.EOB: 569 if (TraceTm.recovery.isDebugEnabled()) { 570 TraceTm.recovery.debug("Howl End of Buffer Record"); 571 } 572 break; 573 case LogRecordType.END_OF_LOG: 574 if (TraceTm.recovery.isDebugEnabled()) { 575 TraceTm.recovery.debug("Howl End of Log Record"); 576 } 577 break; 578 case LogRecordType.XACOMMIT: 579 if (TraceTm.recovery.isDebugEnabled()) { 580 TraceTm.recovery.debug("Howl XA Commit Record"); 581 } 582 tmrecovery.rebuildTransaction ((XALogRecord) lr); 583 break; 584 case LogRecordType.XADONE: 585 if (TraceTm.recovery.isDebugEnabled()) { 586 TraceTm.recovery.debug("Howl XA Done Record"); 587 } 588 break; 589 case LogRecordType.USER: 590 if (TraceTm.recovery.isDebugEnabled()) { 591 TraceTm.recovery.debug("Howl User Record"); 592 } 593 break; 594 default: 595 if (TraceTm.recovery.isDebugEnabled()) { 596 TraceTm.recovery.debug("Unknown Howl LogRecord"); 597 } 598 break; 599 } 600 } 601 602 public void onError(LogException exception) { 603 if (TraceTm.recovery.isDebugEnabled()) { 605 TraceTm.recovery.debug("onError"); 606 } 607 } 608 609 public LogRecord getLogRecord() { 610 if (TraceTm.recovery.isDebugEnabled()) { 611 TraceTm.recovery.debug("getLogRecord"); 612 } 613 return new XALogRecord(120); 614 } 615 } 616 617 620 621 synchronized void howlOpenLog (Properties phowlprop) throws SystemException { 622 623 if (!(xaLog == null)) { 624 if (TraceTm.recovery.isDebugEnabled()) { 625 TraceTm.recovery.debug("Howl Log already opened"); 626 } 627 return; 628 } 629 630 if (TraceTm.recovery.isDebugEnabled()) { 631 TraceTm.recovery.debug("Open howl log"); 632 } 633 634 try { 635 Configuration cfg = new Configuration (phowlprop); 636 xaLog = new XALogger(cfg); 637 } catch (LogConfigurationException e) { 638 TraceTm.jotm.error("XALogger: LogConfigurationException"); 639 throw new SystemException ("LogConfigurationException occured in XALogger() " + e.getMessage()); 640 } catch (IOException e) { 641 TraceTm.jotm.error("XALogger: IOException"); 642 throw new SystemException ("IOException occured in XALogger() " + e.getMessage()); 643 } catch (Exception e) { 644 TraceTm.jotm.error("XALogger: Exception"); 645 throw new SystemException ("Exeception occurred in XALogger() " + e.getMessage()); 646 } 647 648 tmrecovery = new JotmRecovery (); 649 650 xaReplayListener myxarl = new xaReplayListener(); 651 652 if (TraceTm.recovery.isDebugEnabled()) { 653 TraceTm.recovery.debug("xaLog.open"); 654 } 655 656 try { 657 xaLog.open (null); 658 } catch (LogException e) { 659 TraceTm.jotm.error("xaLog.open: LogException"); 660 throw new SystemException ("LogException occured in xaLog.open() " + e.getMessage()); 661 } catch (IOException e) { 662 TraceTm.jotm.error("xaLog.open: IOException"); 663 throw new SystemException ("IOException occured in xaLog.open() " + e.getMessage()); 664 } catch (InterruptedException e) { 665 TraceTm.jotm.error("xaLog.open: InterruptedException"); 666 throw new SystemException ("InterruptedException occured in xaLog.open() " + e.getMessage()); 667 } catch (ClassNotFoundException e) { 668 TraceTm.jotm.error("xaLog.open: ClassNotFoundException"); 669 throw new SystemException ("ClassNotFoundException occured in xaLog.open() " + e.getMessage()); 670 } catch (Exception e) { 671 TraceTm.jotm.error("xaLog.open: Exception " + e.getMessage()); 672 throw new SystemException ("Exception occurred in xaLog.open() " + e.getMessage()); 673 } 674 675 xaLog.replayActiveTx (myxarl); 676 } 677 678 681 682 void howlCloseLog () throws SystemException { 683 684 if (TraceTm.recovery.isDebugEnabled()) { 685 TraceTm.recovery.debug("Close howl log"); 686 } 687 688 if (xaLog == null) return; 689 690 try { 691 xaLog.close(); 692 } catch (IOException e) { 693 TraceTm.jotm.error("xaLog.close: IOException"); 694 throw new SystemException ("IOException occured in xaLog.close() " + e.getMessage()); 695 } catch (InterruptedException e) { 696 TraceTm.jotm.error("xaLog.close: InterruptedException"); 697 throw new SystemException ("InterruptedException occured in xaLog.close() " + e.getMessage()); 698 } 699 700 xaLog = null; 701 702 if (TraceTm.recovery.isDebugEnabled()) { 703 TraceTm.recovery.debug("Howl log closed"); 704 } 705 } 706 707 710 711 public XACommittingTx howlCommitLog (byte [] [] xaCmRec) throws LogException, Exception { 712 if (TraceTm.recovery.isDebugEnabled()) { 713 TraceTm.recovery.debug("Commit howl log"); 714 } 715 return xaLog.putCommit (xaCmRec); 716 } 717 718 721 722 public void howlDoneLog (byte [] [] xaDnRec, XACommittingTx xaCmTx) throws LogException, Exception { 723 if (TraceTm.recovery.isDebugEnabled()) { 724 TraceTm.recovery.debug("Done howl log"); 725 } 726 xaLog.putDone (xaDnRec, xaCmTx); 727 } 728 729 732 733 public void forget () throws LogException, Exception { 734 735 if (!Current.getDefaultRecovery()) { 736 if (TraceTm.recovery.isDebugEnabled()) { 737 TraceTm.recovery.debug("JOTM Recovery is disabled"); 738 } 739 } else { 740 howlCloseLog(); 741 } 742 743 } 744 745 } 746 | Popular Tags |