• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / cdi / #1015

28 May 2024 08:39PM CUT coverage: 93.033%. Remained the same
#1015

Pull #469

github

web-flow
Update dependency org.mybatis:mybatis-parent to v44
Pull Request #469: Update dependency org.mybatis:mybatis-parent to v44

79 of 100 branches covered (79.0%)

227 of 244 relevant lines covered (93.03%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.0
/src/main/java/org/mybatis/cdi/LocalTransactionInterceptor.java
1
/*
2
 *    Copyright 2013-2023 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 org.mybatis.cdi;
17

18
import jakarta.inject.Inject;
19
import jakarta.interceptor.AroundInvoke;
20
import jakarta.interceptor.Interceptor;
21
import jakarta.interceptor.InvocationContext;
22
import jakarta.transaction.HeuristicMixedException;
23
import jakarta.transaction.HeuristicRollbackException;
24
import jakarta.transaction.NotSupportedException;
25
import jakarta.transaction.RollbackException;
26
import jakarta.transaction.SystemException;
27

28
import java.io.Serializable;
29
import java.lang.reflect.InvocationTargetException;
30
import java.lang.reflect.UndeclaredThrowableException;
31

32
import org.apache.ibatis.session.SqlSessionManager;
33

34
/**
35
 * Best-effort interceptor for local transactions. It locates all the instances of {@code SqlSssionManager} and starts
36
 * transactions on all them. It cannot guarantee atomiticy if there is more than one {@code SqlSssionManager}. Use XA
37
 * drivers, a JTA container and the {@link JtaTransactionInterceptor} in that case.
38
 *
39
 * @see JtaTransactionInterceptor
40
 *
41
 * @author Frank David Martínez
42
 */
43
@Transactional
44
@Interceptor
45
public class LocalTransactionInterceptor implements Serializable {
1✔
46

47
  private static final long serialVersionUID = 1L;
48

49
  @Inject
50
  private transient SqlSessionManagerRegistry registry;
51

52
  /**
53
   * Invoke.
54
   *
55
   * @param ctx
56
   *          the ctx
57
   *
58
   * @return the object
59
   *
60
   * @throws Exception
61
   *           the exception
62
   */
63
  @AroundInvoke
64
  public Object invoke(InvocationContext ctx) throws Exception {
65
    Transactional transactional = getTransactionalAnnotation(ctx);
1✔
66
    boolean isInitiator = start(transactional);
1✔
67
    boolean isExternalJta = isTransactionActive();
1✔
68
    if (isInitiator && !isExternalJta) {
1!
69
      beginJta();
1✔
70
    }
71
    boolean needsRollback = transactional.rollbackOnly();
1✔
72
    Object result;
73
    try {
74
      result = ctx.proceed();
1✔
75
    } catch (Exception ex) {
1✔
76
      Exception unwrapped = unwrapException(ex);
1✔
77
      needsRollback = needsRollback || needsRollback(transactional, unwrapped);
1!
78
      throw unwrapped;
1✔
79
    } finally {
80
      if (isInitiator) {
1!
81
        try {
82
          if (needsRollback) {
1✔
83
            rollback(transactional);
1✔
84
          } else {
85
            commit(transactional);
1✔
86
          }
87
        } finally {
88
          close();
1✔
89
          endJta(isExternalJta, needsRollback);
1✔
90
        }
91
      }
92
    }
93
    return result;
1✔
94
  }
95

96
  /**
97
   * Checks if is transaction active.
98
   *
99
   * @return true, if is transaction active
100
   *
101
   * @throws SystemException
102
   *           used by jtaTransactionInterceptor
103
   */
104
  protected boolean isTransactionActive() throws SystemException {
105
    return false;
1✔
106
  }
107

108
  /**
109
   * Begin jta.
110
   *
111
   * @throws NotSupportedException
112
   *           used by jtaTransactionInterceptor
113
   * @throws SystemException
114
   *           used by jtaTransactionInterceptor
115
   */
116
  protected void beginJta() throws NotSupportedException, SystemException {
117
    // nothing to do
118
  }
1✔
119

120
  /**
121
   * End jta.
122
   *
123
   * @param isExternaTransaction
124
   *          the is externa transaction
125
   * @param commit
126
   *          the commit
127
   *
128
   * @throws SystemException
129
   *           used by jtaTransactionInterceptor
130
   * @throws RollbackException
131
   *           used by jtaTransactionInterceptor
132
   * @throws HeuristicMixedException
133
   *           used by jtaTransactionInterceptor
134
   * @throws HeuristicRollbackException
135
   *           used by jtaTransactionInterceptor
136
   */
137
  protected void endJta(boolean isExternaTransaction, boolean commit)
138
      throws SystemException, RollbackException, HeuristicMixedException, HeuristicRollbackException {
139
    // nothing to do
140
  }
1✔
141

142
  private boolean needsRollback(Transactional transactional, Throwable throwable) {
143
    if (RuntimeException.class.isAssignableFrom(throwable.getClass())) {
1✔
144
      return true;
1✔
145
    }
146
    for (Class<? extends Throwable> exceptionClass : transactional.rollbackFor()) {
1✔
147
      if (exceptionClass.isAssignableFrom(throwable.getClass())) {
1✔
148
        return true;
1✔
149
      }
150
    }
151
    return false;
1✔
152
  }
153

154
  protected Transactional getTransactionalAnnotation(InvocationContext ctx) {
155
    Transactional t = ctx.getMethod().getAnnotation(Transactional.class);
1✔
156
    if (t == null) {
1✔
157
      t = ctx.getMethod().getDeclaringClass().getAnnotation(Transactional.class);
1✔
158
    }
159
    return t;
1✔
160
  }
161

162
  private boolean start(Transactional transactional) {
163
    boolean started = false;
1✔
164
    for (SqlSessionManager manager : this.registry.getManagers()) {
1✔
165
      if (!manager.isManagedSessionStarted()) {
1!
166
        manager.startManagedSession(transactional.executorType(),
1✔
167
            transactional.isolation().getTransactionIsolationLevel());
1✔
168
        started = true;
1✔
169
      }
170
    }
1✔
171
    return started;
1✔
172
  }
173

174
  private void commit(Transactional transactional) {
175
    for (SqlSessionManager manager : this.registry.getManagers()) {
1✔
176
      manager.commit(transactional.force());
1✔
177
    }
1✔
178
  }
1✔
179

180
  private void rollback(Transactional transactional) {
181
    for (SqlSessionManager manager : this.registry.getManagers()) {
1✔
182
      manager.rollback(transactional.force());
1✔
183
    }
1✔
184
  }
1✔
185

186
  private void close() {
187
    for (SqlSessionManager manager : this.registry.getManagers()) {
1✔
188
      manager.close();
1✔
189
    }
1✔
190
  }
1✔
191

192
  private Exception unwrapException(Exception wrapped) {
193
    Throwable unwrapped = wrapped;
1✔
194
    while (true) {
195
      if (unwrapped instanceof InvocationTargetException) {
1!
196
        unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
×
197
      } else if (unwrapped instanceof UndeclaredThrowableException) {
1!
198
        unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
×
199
      } else if (!(unwrapped instanceof Exception)) {
1!
200
        return new RuntimeException(unwrapped);
×
201
      } else {
202
        return (Exception) unwrapped;
1✔
203
      }
204
    }
205
  }
206

207
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc