1 21 22 package org.opensubsystems.core.persist.db.transaction; 23 24 import java.sql.Connection ; 25 import java.sql.SQLException ; 26 import java.util.logging.Logger ; 27 28 import javax.transaction.HeuristicMixedException ; 29 import javax.transaction.HeuristicRollbackException ; 30 import javax.transaction.NotSupportedException ; 31 import javax.transaction.RollbackException ; 32 import javax.transaction.Status ; 33 import javax.transaction.SystemException ; 34 import javax.transaction.TransactionManager ; 35 import javax.transaction.UserTransaction ; 36 37 import org.opensubsystems.core.error.OSSDatabaseAccessException; 38 import org.opensubsystems.core.error.OSSException; 39 import org.opensubsystems.core.persist.db.DatabaseConnectionFactoryImpl; 40 import org.opensubsystems.core.persist.db.DatabaseTransactionFactoryImpl; 41 import org.opensubsystems.core.util.GlobalConstants; 42 import org.opensubsystems.core.util.Log; 43 44 307 public class SimpleLocalTransactionFactoryImpl extends DatabaseTransactionFactoryImpl 308 implements UserTransaction 309 { 310 312 315 public static final Integer STATUS_ACTIVE_OBJ 316 = new Integer (Status.STATUS_ACTIVE); 317 318 321 public static final Integer STATUS_COMMITTED_OBJ 322 = new Integer (Status.STATUS_COMMITTED); 323 324 328 public static final Integer STATUS_COMMITTING_OBJ 329 = new Integer (Status.STATUS_COMMITTING); 330 331 335 public static final Integer STATUS_MARKED_ROLLBACK_OBJ 336 = new Integer (Status.STATUS_MARKED_ROLLBACK); 337 338 341 public static final Integer STATUS_NO_TRANSACTION_OBJ 342 = new Integer (Status.STATUS_NO_TRANSACTION); 343 344 347 public static final Integer STATUS_PREPARED_OBJ 348 = new Integer (Status.STATUS_PREPARED); 349 350 354 public static final Integer STATUS_PREPARING_OBJ 355 = new Integer (Status.STATUS_PREPARING); 356 357 361 public static final Integer STATUS_ROLLEDBACK_OBJ 362 = new Integer (Status.STATUS_ROLLEDBACK); 363 364 368 public static final Integer STATUS_ROLLING_BACK_OBJ 369 = new Integer (Status.STATUS_ROLLING_BACK); 370 371 375 public static final Integer STATUS_UNKNOWN_OBJ 376 = new Integer (Status.STATUS_UNKNOWN); 377 378 380 387 private ThreadLocal m_connection; 388 389 393 private ThreadLocal m_realConnection; 394 395 401 private ThreadLocal m_transaction; 402 403 405 408 private static Logger s_logger = Log.getInstance(SimpleLocalTransactionFactoryImpl.class); 409 410 412 417 public SimpleLocalTransactionFactoryImpl( 418 ) throws OSSException 419 { 420 super(); 421 422 m_connection = new ThreadLocal (); 425 m_transaction = new ThreadLocal (); 426 m_realConnection = new ThreadLocal (); 427 } 428 429 431 434 public UserTransaction requestTransaction() 435 { 436 UserTransaction transaction = this; 438 439 if (s_bTransactionMonitor) 440 { 441 transaction = new DelegatingUserTransaction(transaction); 442 } 443 return transaction; 444 } 445 446 449 public void reset( 450 ) throws OSSException 451 { 452 s_logger.severe("About to reset state of transaction manager." + 455 " Hope you know what you are doing."); 456 m_connection = new ThreadLocal (); 457 m_transaction = new ThreadLocal (); 458 m_realConnection = new ThreadLocal (); 459 } 460 461 464 public void stop( 465 ) throws OSSException 466 { 467 } 470 471 474 public TransactionManager getTransactionManager( 475 ) 476 { 477 return null; 481 } 482 483 485 488 public void begin( 489 ) throws NotSupportedException , 490 SystemException 491 { 492 try 493 { 494 if (isTransactionInProgress()) 495 { 496 throw new NotSupportedException ("Cannot start another transaction while" + 497 " one is still in progress."); 498 } 499 else 500 { 501 m_transaction.set(STATUS_ACTIVE_OBJ); 502 503 TransactionalConnection existingConnection; 504 505 existingConnection = (TransactionalConnection)m_connection.get(); 506 if (existingConnection != null) 507 { 508 if (GlobalConstants.ERROR_CHECKING) 513 { 514 assert (!existingConnection.isInTransaction()) 515 : "Connection cannot be already in transaction when" + 516 " transaction is only starting."; 517 } 518 519 try 520 { 521 existingConnection.setUsed(false); 523 existingConnection.setInTransaction(true); 524 } 525 catch (SQLException sqleExc) 526 { 527 SystemException sysExc = new SystemException ( 528 "Cannot associate connection with transaction."); 529 sysExc.initCause(sqleExc); 530 throw sysExc; 531 } 532 } 533 else 534 { 535 } 539 } 540 } 541 catch (OSSException ossExc) 542 { 543 throw new SystemException ("Error occured while retrieving information " + 544 "about transaction status."); 545 } 546 } 547 548 551 public void commit( 552 ) throws RollbackException , 553 HeuristicMixedException , 554 HeuristicRollbackException , 555 SecurityException , 556 IllegalStateException , 557 SystemException 558 { 559 endTransaction(true); 560 } 561 562 565 public int getStatus( 566 ) throws SystemException 567 { 568 Integer iTransactionStatus = (Integer )m_transaction.get(); 569 int iStatus; 570 571 if (iTransactionStatus == null) 572 { 573 iStatus = Status.STATUS_NO_TRANSACTION; 574 } 575 else 576 { 577 iStatus = iTransactionStatus.intValue(); 578 } 579 580 return iStatus; 581 } 582 583 586 public void rollback( 587 ) throws IllegalStateException , 588 SecurityException , 589 SystemException 590 { 591 endTransaction(false); 592 } 593 594 597 public void setRollbackOnly( 598 ) throws IllegalStateException , 599 SystemException 600 { 601 try 602 { 603 if (isTransactionInProgress()) 604 { 605 m_transaction.set(STATUS_MARKED_ROLLBACK_OBJ); 606 } 607 else 608 { 609 throw new IllegalStateException ("No transaction in progress to be marked" + 610 " rollbacked only."); 611 } 612 } 613 catch (OSSException ossExc) 614 { 615 throw new SystemException ("Error occured while retrieving information " + 616 "about transaction status."); 617 } 618 } 619 620 623 public void setTransactionTimeout( 624 int arg0 625 ) throws SystemException 626 { 627 } 630 631 633 656 protected Connection requestTransactionalConnection( 657 boolean bAutoCommit, 658 String strDataSourceName, 659 String strUser, 660 String strPassword, 661 DatabaseConnectionFactoryImpl connectionFactory 662 ) throws OSSDatabaseAccessException 663 { 664 TransactionalConnection existingConnection; 665 Connection existingRealConnection; 666 boolean bTransaction; 667 668 existingConnection = (TransactionalConnection)m_connection.get(); 669 existingRealConnection = (Connection )m_realConnection.get(); 670 try 671 { 672 bTransaction = isTransactionInProgress(); 673 } 674 catch (SystemException sysExc) 675 { 676 throw new OSSDatabaseAccessException( 677 "There was an exception occured while retrieving UserTransaction " + 678 "status.", sysExc); 679 } 680 catch (OSSException osseExc) 681 { 682 throw new OSSDatabaseAccessException( 683 "There was an exception occured while retrieving UserTransaction " + 684 "status.", osseExc); 685 } 686 687 if (existingConnection != null) 688 { 689 if (GlobalConstants.ERROR_CHECKING) 692 { 693 assert (((!existingConnection.isInTransaction()) && (!bTransaction)) 694 || ((existingConnection.isInTransaction()) && (bTransaction))) 695 : "Connection status about transaction in progress doesn't" + 696 " match the reality."; 697 assert existingConnection.verifyConnection(existingRealConnection) 698 : "The real database connection is not the one which is wrapped" + 699 " in transactional wrapper."; 700 } 701 702 String strCurrentDataSourceName; 704 String strExistingDataSourceName; 705 String strExistingUser; 706 String strExistingPassword; 707 708 if (strDataSourceName == null) 709 { 710 strCurrentDataSourceName = connectionFactory.getDefaultDataSourceName(); 711 } 712 else 713 { 714 strCurrentDataSourceName = strDataSourceName; 715 } 716 strExistingDataSourceName = existingConnection.getDataSourceName(); 717 strExistingUser = existingConnection.getUser(); 718 strExistingPassword = existingConnection.getPassword(); 719 720 if (connectionFactory != existingConnection.getConnectionFactory()) 724 { 725 throw new OSSDatabaseAccessException( 726 "Cannot issue connection from the factory for a different" + 727 " connection factory that the factory for which the" + 728 " connection is already issued."); 729 } 730 731 if ((((strCurrentDataSourceName == null) && (strExistingDataSourceName == null)) 732 || ((strCurrentDataSourceName != null) 733 && (strCurrentDataSourceName.equals(strExistingDataSourceName)))) 734 && (((strUser == null) && (strExistingUser == null)) 735 || ((strUser != null) && (strUser.equals(strExistingUser)))) 736 && (((strPassword == null) && (strExistingPassword == null)) 737 || ((strPassword != null) && (strPassword.equals(strExistingPassword))))) 738 { 739 existingConnection.setActive(true); 742 } 743 else 744 { 745 throw new OSSDatabaseAccessException( 749 "Cannot issue connection from the factory for a different" + 750 " user than the user for which the connection is already issued."); 751 } 752 } 753 else 754 { 755 Connection realConnection; 756 757 realConnection = super.requestTransactionalConnection(bAutoCommit, 761 strDataSourceName, strUser, strPassword, 762 connectionFactory); 763 764 if (strDataSourceName == null) 765 { 766 strDataSourceName = connectionFactory.getDefaultDataSourceName(); 767 } 768 769 existingConnection = new TransactionalConnection( 770 realConnection, 771 strDataSourceName, 772 strUser, 773 strPassword, 774 bTransaction, 775 connectionFactory); 776 m_connection.set(existingConnection); 778 m_realConnection.set(realConnection); 781 } 782 783 return existingConnection; 784 } 785 786 789 protected void returnTransactionalConnection( 790 Connection cntDBConnection, 791 DatabaseConnectionFactoryImpl connectionFactory 792 ) 793 { 794 if (cntDBConnection != null) 795 { 796 if (cntDBConnection instanceof TransactionalConnection) 797 { 798 TransactionalConnection connection; 800 Connection realConnection; 801 802 connection = (TransactionalConnection)cntDBConnection; 803 realConnection = (Connection )m_realConnection.get(); 804 if (GlobalConstants.ERROR_CHECKING) 805 { 806 TransactionalConnection existingConnection; 807 existingConnection = (TransactionalConnection)m_connection.get(); 808 809 assert (existingConnection != null) 812 && (existingConnection == connection) : "The returned connection is not the one we think we issued: " + 814 " existing connection is " + existingConnection + 815 " returned connection is " + connection; 816 assert existingConnection.verifyConnection(realConnection) 817 : "The real database connection is not the one which is wrapped" + 818 " in transactional wrapper."; 819 assert connectionFactory == existingConnection.getConnectionFactory() 821 : "Cannot issue connection from the factory for a different" + 822 " connection factory that the factory for which the" + 823 " connection is already issued."; 824 } 825 826 connection.setActive(false); 828 if ((!connection.isInTransaction()) && (!connection.isActive())) 831 { 832 super.returnTransactionalConnection(realConnection, connectionFactory); 836 m_connection.set(null); 838 m_realConnection.set(null); 839 } 840 else 841 { 842 } 847 } 848 else 849 { 850 super.returnTransactionalConnection(cntDBConnection, connectionFactory); 853 } 854 } 855 } 856 857 864 protected void endTransaction( 865 boolean bCommit 866 ) throws SystemException 867 { 868 Integer iTransactionStatus = (Integer )m_transaction.get(); 869 870 if (iTransactionStatus != null) 871 { 872 if (iTransactionStatus.intValue() == Status.STATUS_MARKED_ROLLBACK) 873 { 874 bCommit = false; 876 } 877 878 if (iTransactionStatus.intValue() == Status.STATUS_ACTIVE) 879 { 880 try 881 { 882 TransactionalConnection existingConnection; 883 884 existingConnection = (TransactionalConnection)m_connection.get(); 885 if (existingConnection != null) 886 { 887 if (GlobalConstants.ERROR_CHECKING) 889 { 890 assert existingConnection.isInTransaction() 891 : "The connection is not associated to transaction."; 892 } 893 894 try 898 { 899 existingConnection.setInTransaction(false); 900 if (bCommit) 902 { 903 if (existingConnection.isUsed()) 904 { 905 existingConnection.commit(); 907 } 908 m_transaction.set(STATUS_COMMITTED_OBJ); 910 } 911 else 912 { 913 if (existingConnection.isUsed()) 914 { 915 existingConnection.rollback(); 917 } 918 m_transaction.set(STATUS_ROLLEDBACK_OBJ); 920 } 921 existingConnection.setUsed(false); 924 } 925 catch (SQLException sqleExc) 926 { 927 SystemException sysExc; 928 if (bCommit) 929 { 930 sysExc = new SystemException ( 931 "An error has occured during commit."); 932 } 933 else 934 { 935 sysExc = new SystemException ( 936 "An error has occured during rollback."); 937 } 938 sysExc.initCause(sqleExc); 939 throw sysExc; 940 } 941 if (!existingConnection.isActive()) 942 { 943 Connection realConnection; 946 947 realConnection = (Connection )m_realConnection.get(); 948 if (GlobalConstants.ERROR_CHECKING) 949 { 950 assert existingConnection.verifyConnection(realConnection) 951 : "The real database connection is not the one which is wrapped" + 952 " in transactional wrapper."; 953 } 954 existingConnection.getConnectionFactory().returnNonTransactionalConnection( 957 realConnection); 958 m_connection.set(null); 960 m_realConnection.set(null); 961 } 962 } 963 else 964 { 965 if (bCommit) 969 { 970 m_transaction.set(STATUS_COMMITTED_OBJ); 971 } 972 else 973 { 974 m_transaction.set(STATUS_ROLLEDBACK_OBJ); 975 } 976 } 977 } 978 finally 979 { 980 if (GlobalConstants.ERROR_CHECKING) 986 { 987 iTransactionStatus = (Integer )m_transaction.get(); 988 assert ((iTransactionStatus == STATUS_ROLLEDBACK_OBJ) 990 || (iTransactionStatus == STATUS_COMMITTED_OBJ)) 991 : "Transaction wasn't commited nor rollbacked."; 992 } 993 } 994 } 995 else 996 { 997 if (bCommit) 998 { 999 throw new IllegalStateException ( 1000 "Transaction cannot be commited if it wasn't started."); 1001 } 1002 else 1003 { 1004 throw new IllegalStateException ( 1005 "Transaction cannot be rollbacked if it wasn't started."); 1006 } 1007 } 1008 } 1009 else 1010 { 1011 if (bCommit) 1012 { 1013 throw new IllegalStateException ( 1014 "Transaction cannot be commited if it wasn't started."); 1015 } 1016 else 1017 { 1018 throw new IllegalStateException ( 1019 "Transaction cannot be rollbacked if it wasn't started."); 1020 } 1021 } 1022 } 1023} 1024 | Popular Tags |