001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.transaction;
018:
019: import javax.transaction.Status;
020: import javax.transaction.SystemException;
021: import javax.transaction.TransactionManager;
022: import javax.transaction.UserTransaction;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.compass.core.CompassException;
027: import org.compass.core.CompassSession;
028: import org.compass.core.spi.InternalCompassSession;
029:
030: /**
031: * @author kimchy
032: */
033: public abstract class AbstractJTATransaction extends
034: AbstractTransaction {
035:
036: private static final Log log = LogFactory
037: .getLog(AbstractJTATransaction.class);
038:
039: private UserTransaction ut;
040:
041: /**
042: * Did we start the JTA transaction
043: */
044: private boolean newTransaction;
045:
046: /**
047: * Is this the up most level controlling the Compass transaction
048: */
049: private boolean controllingNewTransaction = false;
050:
051: private boolean commitFailed;
052:
053: private InternalCompassSession session;
054:
055: public AbstractJTATransaction(UserTransaction ut,
056: TransactionFactory transactionFactory) {
057: super (transactionFactory);
058: this .ut = ut;
059: }
060:
061: public void begin(InternalCompassSession session,
062: TransactionManager transactionManager,
063: TransactionIsolation transactionIsolation)
064: throws CompassException {
065:
066: try {
067: this .session = session;
068: controllingNewTransaction = true;
069: newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
070: if (newTransaction) {
071: if (log.isDebugEnabled()) {
072: log
073: .debug("Beginning new JTA transaction, and a new compass transaction on thread ["
074: + Thread.currentThread().getName()
075: + "] with isolation ["
076: + transactionIsolation + "]");
077: }
078: session.getSearchEngine().begin(transactionIsolation);
079: ut.begin();
080: } else {
081: // joining an exisiting transaction
082: session.getSearchEngine().begin(transactionIsolation);
083: if (log.isDebugEnabled()) {
084: log
085: .debug("Joining an existing JTA transaction, starting a new compass transaction on thread ["
086: + Thread.currentThread().getName()
087: + "] with isolation ["
088: + transactionIsolation
089: + "] and status ["
090: + ut.getStatus()
091: + "]");
092: }
093: }
094: javax.transaction.Transaction tx = transactionManager
095: .getTransaction();
096: doBindToTransaction(tx, session, newTransaction);
097: } catch (Exception e) {
098: throw new TransactionException(
099: "Begin failed with exception", e);
100: }
101: setBegun(true);
102: }
103:
104: protected abstract void doBindToTransaction(
105: javax.transaction.Transaction tx,
106: InternalCompassSession session, boolean newTransaction)
107: throws Exception;
108:
109: /**
110: * Called by the factory when joining an already running compass transaction
111: */
112: public void join(InternalCompassSession session)
113: throws CompassException {
114: this .session = session;
115: controllingNewTransaction = false;
116: if (log.isDebugEnabled()) {
117: log
118: .debug("Joining an existing compass transcation on thread ["
119: + Thread.currentThread().getName() + "]");
120: }
121: }
122:
123: protected void doCommit() throws CompassException {
124:
125: if (!controllingNewTransaction) {
126: if (log.isDebugEnabled()) {
127: log
128: .debug("Not committing JTA transaction since compass does not control it on thread ["
129: + Thread.currentThread().getName()
130: + "]");
131: }
132: return;
133: }
134:
135: if (newTransaction) {
136: if (log.isDebugEnabled()) {
137: log
138: .debug("Committing JTA transaction controlled by compass on thread ["
139: + Thread.currentThread().getName()
140: + "]");
141: }
142: try {
143: ut.commit();
144: } catch (Exception e) {
145: commitFailed = true;
146: // so the transaction is already rolled back, by JTA spec
147: throw new TransactionException("Commit failed", e);
148: }
149: } else {
150: if (log.isDebugEnabled()) {
151: log
152: .debug("Commit called, let JTA synchronization commit the transaciton on thread ["
153: + Thread.currentThread().getName()
154: + "]");
155: }
156: }
157: }
158:
159: protected void doRollback() throws CompassException {
160:
161: try {
162: if (newTransaction) {
163: if (log.isDebugEnabled()) {
164: log
165: .debug("Rolling back JTA transaction controlled by compass on thread ["
166: + Thread.currentThread().getName()
167: + "]");
168: }
169: if (!commitFailed)
170: ut.rollback();
171: } else {
172: if (log.isDebugEnabled()) {
173: log
174: .debug("Marking JTA transaction as rolled back since compass controlls it on thread ["
175: + Thread.currentThread().getName()
176: + "]");
177: }
178: ut.setRollbackOnly();
179: }
180: } catch (Exception e) {
181: throw new TransactionException(
182: "Rollback failed with exception", e);
183: }
184: }
185:
186: public boolean wasRolledBack() throws TransactionException {
187:
188: if (!isBegun())
189: return false;
190: if (commitFailed)
191: return true;
192:
193: final int status;
194: try {
195: status = ut.getStatus();
196: } catch (SystemException se) {
197: throw new TransactionException(
198: "Could not determine transaction status", se);
199: }
200: if (status == Status.STATUS_UNKNOWN) {
201: throw new TransactionException(
202: "Could not determine transaction status");
203: } else {
204: return status == Status.STATUS_MARKED_ROLLBACK
205: || status == Status.STATUS_ROLLING_BACK
206: || status == Status.STATUS_ROLLEDBACK;
207: }
208: }
209:
210: public boolean wasCommitted() throws TransactionException {
211:
212: if (!isBegun() || commitFailed)
213: return false;
214:
215: final int status;
216: try {
217: status = ut.getStatus();
218: } catch (SystemException se) {
219: throw new TransactionException(
220: "Could not determine transaction status: ", se);
221: }
222: if (status == Status.STATUS_UNKNOWN) {
223: throw new TransactionException(
224: "Could not determine transaction status");
225: } else {
226: return status == Status.STATUS_COMMITTED;
227: }
228: }
229:
230: public CompassSession getSession() {
231: return this.session;
232: }
233: }
|