001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2019 microBean. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.microbean.narayana.jta.cdi; 018 019import javax.enterprise.context.ApplicationScoped; 020import javax.enterprise.context.Destroyed; 021import javax.enterprise.context.Initialized; 022 023import javax.enterprise.event.Event; 024 025import javax.inject.Inject; 026 027import javax.transaction.HeuristicMixedException; 028import javax.transaction.HeuristicRollbackException; 029import javax.transaction.NotSupportedException; 030import javax.transaction.RollbackException; 031import javax.transaction.SystemException; 032import javax.transaction.Transaction; 033import javax.transaction.TransactionManager; // for javadoc only 034import javax.transaction.TransactionScoped; 035 036import com.arjuna.ats.jta.common.JTAEnvironmentBean; 037 038/** 039 * A {@link DelegatingTransactionManager} in {@linkplain 040 * ApplicationScoped application scope} that uses the return value 041 * that results from invoking the {@link 042 * JTAEnvironmentBean#getTransactionManager()} method as its backing 043 * implementation. 044 * 045 * @author <a href="https://about.me/lairdnelson" 046 * target="_parent">Laird Nelson</a> 047 * 048 * @see com.arjuna.ats.jta.common.JTAEnvironmentBean#getTransactionManager() 049 */ 050@ApplicationScoped 051public class NarayanaTransactionManager extends DelegatingTransactionManager { 052 053 private final Event<Transaction> transactionScopeInitializedBroadcaster; 054 055 private final Event<Object> transactionScopeDestroyedBroadcaster; 056 057 /** 058 * Creates a new, <strong>nonfunctional</strong> {@link 059 * NarayanaTransactionManager}. 060 * 061 * <p>This constructor exists only to conform with section 3.11 of 062 * the CDI specification.</p> 063 * 064 * @deprecated This constructor exists only to conform with section 065 * 3.11 of the CDI specification; please use the {@link 066 * #NarayanaTransactionManager(JTAEnvironmentBean, Event, Event)} 067 * constructor instead. 068 */ 069 @Deprecated 070 protected NarayanaTransactionManager() { 071 super(null); 072 this.transactionScopeInitializedBroadcaster = null; 073 this.transactionScopeDestroyedBroadcaster = null; 074 } 075 076 /** 077 * Creates a new {@link NarayanaTransactionManager}. 078 * 079 * @param jtaEnvironmentBean a {@link JTAEnvironmentBean} used to 080 * acquire this {@link NarayanaTransactionManager}'s delegate; must 081 * not be {@code null} 082 * 083 * @param transactionScopeInitializedBroadcaster an {@link Event} 084 * capable of {@linkplain Event#fire(Object) firing} {@link 085 * Transaction} instances; may be {@code null} 086 * 087 * @param transactionScopeDestroyedBroadcaster an {@link Event} 088 * capable of {@linkplain Event#fire(Object) firing} {@link Object} 089 * instances; may be {@code null} 090 * 091 * @exception NullPointerException if {@code jtaEnvironmentBean} is 092 * {@code null} 093 * 094 * @see #begin() 095 * 096 * @see #commit() 097 * 098 * @see #rollback() 099 */ 100 @Inject 101 public NarayanaTransactionManager(final JTAEnvironmentBean jtaEnvironmentBean, 102 @Initialized(TransactionScoped.class) 103 final Event<Transaction> transactionScopeInitializedBroadcaster, 104 @Destroyed(TransactionScoped.class) 105 final Event<Object> transactionScopeDestroyedBroadcaster) { 106 super(jtaEnvironmentBean.getTransactionManager()); 107 this.transactionScopeInitializedBroadcaster = transactionScopeInitializedBroadcaster; 108 this.transactionScopeDestroyedBroadcaster = transactionScopeDestroyedBroadcaster; 109 } 110 111 /** 112 * Overrides {@link DelegatingTransactionManager#begin()} to 113 * additionally {@linkplain Event#fire(Object) fire} an {@link 114 * Object} representing the {@linkplain Initialized initialization} 115 * of the {@linkplain TransactionScoped transaction scope}. 116 * 117 * @exception NotSupportedException if the thread is already 118 * associated with a transaction and this {@link TransactionManager} 119 * implementation does not support nested transactions 120 * 121 * @exception SystemException if this {@link TransactionManager} 122 * encounters an unexpected error condition 123 * 124 * @see DelegatingTransactionManager#begin() 125 * 126 * @see Event#fire(Object) 127 * 128 * @see Initialized 129 * 130 * @see TransactionScoped 131 */ 132 @Override 133 public void begin() throws NotSupportedException, SystemException { 134 super.begin(); 135 if (this.transactionScopeInitializedBroadcaster != null) { 136 this.transactionScopeInitializedBroadcaster.fire(this.getTransaction()); 137 } 138 } 139 140 /** 141 * Overrides {@link DelegatingTransactionManager#commit()} to 142 * additionally {@linkplain Event#fire(Object) fire} an {@link 143 * Object} representing the {@linkplain Destroyed destruction} 144 * of the {@linkplain TransactionScoped transaction scope}. 145 * 146 * @exception RollbackException if the transaction has been rolled 147 * back rather than committed 148 * 149 * @exception HeuristicMixedException if a heuristic decision was 150 * made and that some relevant updates have been committed while 151 * others have been rolled back 152 * 153 * @exception HeuristicRollbackException if a heuristic decision was 154 * made and all relevant updates have been rolled back 155 * 156 * @exception SecurityException if the thread is not allowed to 157 * commit the transaction 158 * 159 * @exception IllegalStateException if the current thread is not 160 * associated with a transaction 161 * 162 * @exception SystemException if this {@link TransactionManager} 163 * encounters an unexpected error condition 164 * 165 * @see DelegatingTransactionManager#commit() 166 * 167 * @see Event#fire(Object) 168 * 169 * @see Destroyed 170 * 171 * @see TransactionScoped 172 */ 173 @Override 174 public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SystemException { 175 try { 176 super.commit(); 177 } finally { 178 if (this.transactionScopeDestroyedBroadcaster != null) { 179 this.transactionScopeDestroyedBroadcaster.fire(this.toString()); 180 } 181 } 182 } 183 184 /** 185 * Overrides {@link DelegatingTransactionManager#rollback()} to 186 * additionally {@linkplain Event#fire(Object) fire} an {@link 187 * Object} representing the {@linkplain Destroyed destruction} 188 * of the {@linkplain TransactionScoped transaction scope}. 189 * 190 * @exception SecurityException if the thread is not allowed to roll 191 * back the transaction 192 * 193 * @exception IllegalStateException if the current thread is not 194 * associated with a transaction 195 * 196 * @exception SystemException if this {@link TransactionManager} 197 * encounters an unexpected error condition 198 * 199 * @see DelegatingTransactionManager#rollback() 200 * 201 * @see Event#fire(Object) 202 * 203 * @see Destroyed 204 * 205 * @see TransactionScoped 206 */ 207 @Override 208 public void rollback() throws SystemException { 209 try { 210 super.rollback(); 211 } finally { 212 if (this.transactionScopeDestroyedBroadcaster != null) { 213 this.transactionScopeDestroyedBroadcaster.fire(this.toString()); 214 } 215 } 216 } 217 218}