View Javadoc
1   /*
2    * Copyright 2004-2026 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.ibatis.sqlmap.engine.transaction.jta;
17  
18  import com.ibatis.common.jdbc.logging.ConnectionLogProxy;
19  import com.ibatis.common.logging.Log;
20  import com.ibatis.common.logging.LogFactory;
21  import com.ibatis.sqlmap.engine.transaction.IsolationLevel;
22  import com.ibatis.sqlmap.engine.transaction.Transaction;
23  import com.ibatis.sqlmap.engine.transaction.TransactionException;
24  
25  import java.sql.Connection;
26  import java.sql.SQLException;
27  
28  import javax.sql.DataSource;
29  import javax.transaction.Status;
30  import javax.transaction.UserTransaction;
31  
32  /**
33   * The Class JtaTransaction.
34   */
35  public class JavaxTransaction implements Transaction {
36  
37    /** The Constant connectionLog. */
38    private static final Log connectionLog = LogFactory.getLog(Connection.class);
39  
40    /** The user transaction. */
41    private UserTransaction userTransaction;
42  
43    /** The data source. */
44    private DataSource dataSource;
45  
46    /** The connection. */
47    private Connection connection;
48  
49    /** The isolation level. */
50    private IsolationLevel isolationLevel = new IsolationLevel();
51  
52    /** The commmitted. */
53    private boolean commmitted = false;
54  
55    /** The new transaction. */
56    private boolean newTransaction = false;
57  
58    /**
59     * Instantiates a new jta transaction.
60     *
61     * @param utx
62     *          the utx
63     * @param ds
64     *          the ds
65     * @param isolationLevel
66     *          the isolation level
67     *
68     * @throws TransactionException
69     *           the transaction exception
70     */
71    public JavaxTransaction(UserTransaction utx, DataSource ds, int isolationLevel) throws TransactionException {
72      // Check parameters
73      userTransaction = utx;
74      dataSource = ds;
75      if (userTransaction == null) {
76        throw new TransactionException("JtaTransaction initialization failed.  UserTransaction was null.");
77      }
78      if (dataSource == null) {
79        throw new TransactionException("JtaTransaction initialization failed.  DataSource was null.");
80      }
81      this.isolationLevel.setIsolationLevel(isolationLevel);
82    }
83  
84    /**
85     * Inits the.
86     *
87     * @throws TransactionException
88     *           the transaction exception
89     * @throws SQLException
90     *           the SQL exception
91     */
92    private void init() throws TransactionException, SQLException {
93      // Start JTA Transaction
94      try {
95        newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
96        if (newTransaction) {
97          userTransaction.begin();
98        }
99      } catch (Exception e) {
100       throw new TransactionException("JtaTransaction could not start transaction.  Cause: ", e);
101     }
102 
103     // Open JDBC Connection
104     connection = dataSource.getConnection();
105     if (connection == null) {
106       throw new TransactionException(
107           "JtaTransaction could not start transaction.  Cause: The DataSource returned a null connection.");
108     }
109     // Isolation Level
110     isolationLevel.applyIsolationLevel(connection);
111     // AutoCommit
112     if (connection.getAutoCommit()) {
113       connection.setAutoCommit(false);
114     }
115     // Debug
116     if (connectionLog.isDebugEnabled()) {
117       connection = ConnectionLogProxy.newInstance(connection);
118     }
119   }
120 
121   @Override
122   public void commit() throws SQLException, TransactionException {
123     if (connection != null) {
124       if (commmitted) {
125         throw new TransactionException(
126             "JtaTransaction could not commit because this transaction has already been committed.");
127       }
128       try {
129         if (newTransaction) {
130           userTransaction.commit();
131         }
132       } catch (Exception e) {
133         throw new TransactionException("JtaTransaction could not commit.  Cause: ", e);
134       }
135       commmitted = true;
136     }
137   }
138 
139   @Override
140   public void rollback() throws SQLException, TransactionException {
141     if (connection != null && !commmitted) {
142       try {
143         if (userTransaction != null) {
144           if (newTransaction) {
145             userTransaction.rollback();
146           } else {
147             userTransaction.setRollbackOnly();
148           }
149         }
150       } catch (Exception e) {
151         throw new TransactionException("JtaTransaction could not rollback.  Cause: ", e);
152       }
153     }
154   }
155 
156   @Override
157   public void close() throws SQLException, TransactionException {
158     if (connection != null) {
159       try {
160         isolationLevel.restoreIsolationLevel(connection);
161       } finally {
162         connection.close();
163         connection = null;
164       }
165     }
166   }
167 
168   @Override
169   public Connection getConnection() throws SQLException, TransactionException {
170     if (connection == null) {
171       init();
172     }
173     return connection;
174   }
175 
176 }