001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.kernel;
020:
021: import javax.transaction.NotSupportedException;
022: import javax.transaction.Status;
023: import javax.transaction.Synchronization;
024: import javax.transaction.SystemException;
025: import javax.transaction.Transaction;
026: import javax.transaction.TransactionManager;
027: import javax.transaction.xa.XAResource;
028:
029: import org.apache.openjpa.ee.AbstractManagedRuntime;
030: import org.apache.openjpa.ee.ManagedRuntime;
031: import org.apache.openjpa.lib.util.Localizer;
032: import org.apache.openjpa.util.InternalException;
033: import org.apache.openjpa.util.InvalidStateException;
034: import org.apache.openjpa.util.StoreException;
035: import org.apache.openjpa.util.UserException;
036:
037: /**
038: * Uses a local implementation of the {@link TransactionManager} interface.
039: * This manager is valid only for a single {@link Broker}.
040: * It duplicates non-managed transaction control.
041: *
042: * @author Abe White
043: */
044: class LocalManagedRuntime extends AbstractManagedRuntime implements
045: ManagedRuntime, TransactionManager, Transaction {
046:
047: private static final Localizer _loc = Localizer
048: .forPackage(LocalManagedRuntime.class);
049:
050: private Synchronization _broker = null;
051: private Synchronization _factorySync = null;
052: private boolean _active = false;
053: private Throwable _rollbackOnly = null;
054:
055: /**
056: * Constructor. Provide broker that will be requesting managed
057: * transaction info.
058: */
059: public LocalManagedRuntime(Broker broker) {
060: _broker = broker;
061: }
062:
063: public TransactionManager getTransactionManager() {
064: return this ;
065: }
066:
067: public synchronized void begin() {
068: if (_active)
069: throw new InvalidStateException(_loc.get("active"));
070: _active = true;
071: }
072:
073: public synchronized void commit() {
074: if (!_active)
075: throw new InvalidStateException(_loc.get("not-active"));
076:
077: // try to invoke before completion in preparation for commit
078: RuntimeException err = null;
079: if (_rollbackOnly == null) {
080: try {
081: _broker.beforeCompletion();
082: if (_factorySync != null)
083: _factorySync.beforeCompletion();
084: } catch (RuntimeException re) {
085: _rollbackOnly = re;
086: err = re;
087: }
088: } else
089: // previously marked rollback only
090: err = new StoreException(_loc.get("marked-rollback"))
091: .setCause(_rollbackOnly).setFatal(true);
092:
093: if (_rollbackOnly == null) {
094: try {
095: _broker.afterCompletion(Status.STATUS_COMMITTED);
096: notifyAfterCompletion(Status.STATUS_COMMITTED);
097: } catch (RuntimeException re) {
098: if (err == null)
099: err = re;
100: }
101: }
102:
103: // if we haven't managed to commit, rollback
104: if (_active) {
105: try {
106: rollback();
107: } catch (RuntimeException re) {
108: if (err == null)
109: err = re;
110: }
111: }
112:
113: // throw the first exception we encountered, if any
114: if (err != null)
115: throw err;
116: }
117:
118: public synchronized void rollback() {
119: if (!_active)
120: throw new InvalidStateException(_loc.get("not-active"));
121:
122: // rollback broker
123: RuntimeException err = null;
124: try {
125: _broker.afterCompletion(Status.STATUS_ROLLEDBACK);
126: } catch (RuntimeException re) {
127: err = re;
128: }
129:
130: // rollback synch, even if broker throws exception
131: try {
132: notifyAfterCompletion(Status.STATUS_ROLLEDBACK);
133: } catch (RuntimeException re) {
134: if (err == null)
135: err = re;
136: }
137:
138: if (err != null)
139: throw err;
140: }
141:
142: /**
143: * Notifies the factory sync that the transaction has ended with
144: * the given status. Clears all transaction state regardless
145: * of any exceptions during the callback.
146: */
147: private void notifyAfterCompletion(int status) {
148: _active = false;
149:
150: try {
151: if (_factorySync != null)
152: _factorySync.afterCompletion(status);
153: } finally {
154: _rollbackOnly = null;
155: _factorySync = null;
156: }
157: }
158:
159: public synchronized void setRollbackOnly() {
160: setRollbackOnly(new UserException());
161: }
162:
163: public void setRollbackOnly(Throwable cause) {
164: _rollbackOnly = cause;
165: }
166:
167: public Throwable getRollbackCause() {
168: return _rollbackOnly;
169: }
170:
171: public synchronized int getStatus() {
172: if (_rollbackOnly != null)
173: return Status.STATUS_MARKED_ROLLBACK;
174: if (_active)
175: return Status.STATUS_ACTIVE;
176: return Status.STATUS_NO_TRANSACTION;
177: }
178:
179: public Transaction getTransaction() {
180: return this ;
181: }
182:
183: public void resume(Transaction tobj) throws SystemException {
184: throw new SystemException(NotSupportedException.class.getName());
185: }
186:
187: public void setTransactionTimeout(int sec) throws SystemException {
188: throw new SystemException(NotSupportedException.class.getName());
189: }
190:
191: public Transaction suspend() throws SystemException {
192: throw new SystemException(NotSupportedException.class.getName());
193: }
194:
195: public boolean delistResource(XAResource xaRes, int flag)
196: throws SystemException {
197: throw new SystemException(NotSupportedException.class.getName());
198: }
199:
200: public boolean enlistResource(XAResource xaRes)
201: throws SystemException {
202: throw new SystemException(NotSupportedException.class.getName());
203: }
204:
205: public synchronized void registerSynchronization(
206: Synchronization sync) {
207: if (sync == _broker)
208: return;
209: if (_factorySync != null)
210: throw new InternalException();
211: _factorySync = sync;
212: }
213: }
|