1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.kernel;
20
21 import javax.transaction.NotSupportedException;
22 import javax.transaction.Status;
23 import javax.transaction.Synchronization;
24 import javax.transaction.SystemException;
25 import javax.transaction.Transaction;
26 import javax.transaction.TransactionManager;
27 import javax.transaction.xa.XAResource;
28
29 import org.apache.openjpa.ee.AbstractManagedRuntime;
30 import org.apache.openjpa.ee.ManagedRuntime;
31 import org.apache.openjpa.lib.util.Localizer;
32 import org.apache.openjpa.util.InternalException;
33 import org.apache.openjpa.util.InvalidStateException;
34 import org.apache.openjpa.util.StoreException;
35 import org.apache.openjpa.util.UserException;
36
37 /**
38 * Uses a local implementation of the {@link TransactionManager} interface.
39 * This manager is valid only for a single {@link Broker}.
40 * It duplicates non-managed transaction control.
41 *
42 * @author Abe White
43 */
44 class LocalManagedRuntime extends AbstractManagedRuntime
45 implements ManagedRuntime, TransactionManager, Transaction {
46
47 private static final Localizer _loc = Localizer.forPackage
48 (LocalManagedRuntime.class);
49
50 private Synchronization _broker = null;
51 private Synchronization _factorySync = null;
52 private boolean _active = false;
53 private Throwable _rollbackOnly = null;
54
55 /**
56 * Constructor. Provide broker that will be requesting managed
57 * transaction info.
58 */
59 public LocalManagedRuntime(Broker broker) {
60 _broker = broker;
61 }
62
63 public TransactionManager getTransactionManager() {
64 return this;
65 }
66
67 public synchronized void begin() {
68 if (_active)
69 throw new InvalidStateException(_loc.get("active"));
70 _active = true;
71 }
72
73 public synchronized void commit() {
74 if (!_active)
75 throw new InvalidStateException(_loc.get("not-active"));
76
77 // try to invoke before completion in preparation for commit
78 RuntimeException err = null;
79 if (_rollbackOnly == null) {
80 try {
81 _broker.beforeCompletion();
82 if (_factorySync != null)
83 _factorySync.beforeCompletion();
84 } catch (RuntimeException re) {
85 _rollbackOnly = re;
86 err = re;
87 }
88 } else // previously marked rollback only
89 err = new StoreException(_loc.get("marked-rollback")).
90 setCause(_rollbackOnly).setFatal(true);
91
92 if (_rollbackOnly == null) {
93 try {
94 _broker.afterCompletion(Status.STATUS_COMMITTED);
95 notifyAfterCompletion(Status.STATUS_COMMITTED);
96 } catch (RuntimeException re) {
97 if (err == null)
98 err = re;
99 }
100 }
101
102 // if we haven't managed to commit, rollback
103 if (_active) {
104 try {
105 rollback();
106 } catch (RuntimeException re) {
107 if (err == null)
108 err = re;
109 }
110 }
111
112 // throw the first exception we encountered, if any
113 if (err != null)
114 throw err;
115 }
116
117 public synchronized void rollback() {
118 if (!_active)
119 throw new InvalidStateException(_loc.get("not-active"));
120
121 // rollback broker
122 RuntimeException err = null;
123 try {
124 _broker.afterCompletion(Status.STATUS_ROLLEDBACK);
125 } catch (RuntimeException re) {
126 err = re;
127 }
128
129 // rollback synch, even if broker throws exception
130 try {
131 notifyAfterCompletion(Status.STATUS_ROLLEDBACK);
132 } catch (RuntimeException re) {
133 if (err == null)
134 err = re;
135 }
136
137 if (err != null)
138 throw err;
139 }
140
141 /**
142 * Notifies the factory sync that the transaction has ended with
143 * the given status. Clears all transaction state regardless
144 * of any exceptions during the callback.
145 */
146 private void notifyAfterCompletion(int status) {
147 _active = false;
148
149 try {
150 if (_factorySync != null)
151 _factorySync.afterCompletion(status);
152 } finally {
153 _rollbackOnly = null;
154 _factorySync = null;
155 }
156 }
157
158 public synchronized void setRollbackOnly() {
159 setRollbackOnly(new UserException());
160 }
161
162 public void setRollbackOnly(Throwable cause) {
163 _rollbackOnly = cause;
164 }
165
166 public Throwable getRollbackCause() {
167 return _rollbackOnly;
168 }
169
170 public synchronized int getStatus() {
171 if (_rollbackOnly != null)
172 return Status.STATUS_MARKED_ROLLBACK;
173 if (_active)
174 return Status.STATUS_ACTIVE;
175 return Status.STATUS_NO_TRANSACTION;
176 }
177
178 public Transaction getTransaction() {
179 return this;
180 }
181
182 public void resume(Transaction tobj)
183 throws SystemException {
184 throw new SystemException(NotSupportedException.class.getName());
185 }
186
187 public void setTransactionTimeout(int sec)
188 throws SystemException {
189 throw new SystemException(NotSupportedException.class.getName());
190 }
191
192 public Transaction suspend()
193 throws SystemException {
194 throw new SystemException(NotSupportedException.class.getName());
195 }
196
197 public boolean delistResource(XAResource xaRes, int flag)
198 throws SystemException {
199 throw new SystemException(NotSupportedException.class.getName());
200 }
201
202 public boolean enlistResource(XAResource xaRes)
203 throws SystemException {
204 throw new SystemException(NotSupportedException.class.getName());
205 }
206
207 public synchronized void registerSynchronization(Synchronization sync) {
208 if (sync == _broker)
209 return;
210 if (_factorySync != null)
211 throw new InternalException();
212 _factorySync = sync;
213 }
214 }
215