001: package org.apache.ojb.odmg;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import org.apache.ojb.broker.OJBRuntimeException;
019: import org.apache.ojb.broker.util.configuration.Configuration;
020: import org.apache.ojb.broker.util.logging.Logger;
021: import org.apache.ojb.broker.util.logging.LoggerFactory;
022: import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryException;
023: import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryFactory;
024: import org.apache.commons.lang.SystemUtils;
025: import org.odmg.TransactionNotInProgressException;
026:
027: import javax.transaction.Status;
028: import javax.transaction.SystemException;
029: import javax.transaction.Transaction;
030: import javax.transaction.TransactionManager;
031: import java.lang.ref.WeakReference;
032:
033: /**
034: * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
035: *
036: * In an app server environment, where we have a transaction manager, we
037: * use the transactionmanager and it's associated JTA transaction to associate
038: * with the ODMG transaction. So the key is retrieved by calling getTransaction
039: * on the transactionManager
040: */
041: public class JTATxManager implements OJBTxManager {
042: private Logger log = LoggerFactory.getLogger(JTATxManager.class);
043: private static ThreadLocal txRepository = new ThreadLocal();
044:
045: /**
046: * Remove the ODMG transaction from the transaction buffer
047: * ODMG transactions are associated with JTA transactions via a map
048: */
049: public void deregisterTx(Object transaction) {
050: // TxBuffer buf = (TxBuffer) txRepository.get();
051: // if (buf != null)
052: // {
053: // buf.setInternTx(null);
054: // }
055: txRepository.set(null);
056: }
057:
058: public void registerTx(TransactionImpl odmgTrans) {
059: if (log.isDebugEnabled())
060: log.debug("registerSynchronization was called");
061: Transaction transaction = null;
062: try {
063: transaction = getJTATransaction();
064: } catch (SystemException e) {
065: log.error(
066: "Obtain current transaction from container failed",
067: e);
068: }
069: if (transaction == null) {
070: log
071: .error("Cannot get the external transaction from the external TM");
072: throw new TransactionNotInProgressException(
073: "No external transaction found");
074: }
075: if (log.isDebugEnabled()) {
076: log
077: .debug("registerSynchronization was called with parameters"
078: + SystemUtils.LINE_SEPARATOR
079: + "J2EETransactionImpl: "
080: + odmgTrans
081: + SystemUtils.LINE_SEPARATOR
082: + "Transaction: " + transaction);
083: }
084: registerSynchronization(odmgTrans, transaction);
085: }
086:
087: /**
088: * Do synchronization of the given J2EE ODMG Transaction
089: */
090: private void registerSynchronization(TransactionImpl odmgTrans,
091: Transaction transaction) {
092: // todo only need for development
093: if (odmgTrans == null || transaction == null) {
094: log
095: .error("One of the given parameters was null --> cannot do synchronization!"
096: + " omdg transaction was null: "
097: + (odmgTrans == null)
098: + ", external transaction was null: "
099: + (transaction == null));
100: return;
101: }
102:
103: int status = -1; // default status.
104: try {
105: status = transaction.getStatus();
106: if (status != Status.STATUS_ACTIVE) {
107: throw new OJBRuntimeException(
108: "Transaction synchronization failed - wrong status of external container tx: "
109: + getStatusString(status));
110: }
111: } catch (SystemException e) {
112: throw new OJBRuntimeException(
113: "Can't read status of external tx", e);
114: }
115:
116: try {
117: //Sequence of the following method calls is significant
118: // 1. register the synchronization with the ODMG notion of a transaction.
119: transaction
120: .registerSynchronization((J2EETransactionImpl) odmgTrans);
121: // 2. mark the ODMG transaction as being in a JTA Transaction
122: // Associate external transaction with the odmg transaction.
123: txRepository.set(new TxBuffer(odmgTrans, transaction));
124: } catch (Exception e) {
125: log
126: .error(
127: "Cannot associate PersistenceBroker with running Transaction",
128: e);
129: throw new OJBRuntimeException(
130: "Transaction synchronization failed - wrong status of external container tx",
131: e);
132: }
133: }
134:
135: private static String getStatusString(int status) {
136: switch (status) {
137: case Status.STATUS_ACTIVE:
138: return "STATUS_ACTIVE";
139: case Status.STATUS_COMMITTED:
140: return "STATUS_COMMITTED";
141: case Status.STATUS_COMMITTING:
142: return "STATUS_COMMITTING";
143: case Status.STATUS_MARKED_ROLLBACK:
144: return "STATUS_MARKED_ROLLBACK";
145: case Status.STATUS_NO_TRANSACTION:
146: return "STATUS_NO_TRANSACTION";
147: case Status.STATUS_PREPARED:
148: return "STATUS_PREPARED";
149: case Status.STATUS_PREPARING:
150: return "STATUS_PREPARING";
151: case Status.STATUS_ROLLEDBACK:
152: return "STATUS_ROLLEDBACK";
153: case Status.STATUS_ROLLING_BACK:
154: return "STATUS_ROLLING_BACK";
155: case Status.STATUS_UNKNOWN:
156: return "STATUS_UNKNOWN";
157: default:
158: return "NO STATUS FOUND";
159: }
160: }
161:
162: /**
163: * Return the TransactionManager of the external app
164: */
165: private TransactionManager getTransactionManager() {
166: TransactionManager retval = null;
167: try {
168: if (log.isDebugEnabled())
169: log.debug("getTransactionManager called");
170: retval = TransactionManagerFactoryFactory.instance()
171: .getTransactionManager();
172: } catch (TransactionManagerFactoryException e) {
173: log
174: .warn(
175: "Exception trying to obtain TransactionManager from Factory",
176: e);
177: e.printStackTrace();
178: }
179: return retval;
180: }
181:
182: public Transaction getJTATransaction() throws SystemException {
183: if (log.isDebugEnabled())
184: log.debug("getTransaction called");
185: if (getTransactionManager() == null) {
186: log.warn("TransactionManager was null");
187: return null;
188: }
189: return getTransactionManager().getTransaction();
190: }
191:
192: /**
193: * Returns the current transaction based on the JTA Transaction.
194: * @throws org.odmg.TransactionNotInProgressException if no transaction was found.
195: */
196: public TransactionImpl getCurrentTransaction() {
197: TransactionImpl retval = getTransaction();
198: if (null == retval) {
199: throw new TransactionNotInProgressException(
200: "Calling method needed transaction, but no transaction found via TransactionManager");
201: }
202: return retval;
203: }
204:
205: /**
206: * Returns the current transaction based on the JTA Transaction or <code>null</code>
207: * if no transaction was found.
208: */
209: public TransactionImpl getTransaction() {
210: TxBuffer buf = (TxBuffer) txRepository.get();
211: return buf != null ? buf.getInternTx() : null;
212: }
213:
214: /**
215: * Abort an active extern transaction associated with the given PB.
216: */
217: public void abortExternalTx(TransactionImpl odmgTrans) {
218: if (log.isDebugEnabled())
219: log.debug("abortExternTransaction was called");
220: if (odmgTrans == null)
221: return;
222: TxBuffer buf = (TxBuffer) txRepository.get();
223: Transaction extTx = buf != null ? buf.getExternTx() : null;
224: try {
225: if (extTx != null
226: && extTx.getStatus() == Status.STATUS_ACTIVE) {
227: if (log.isDebugEnabled()) {
228: log.debug("Set extern transaction to rollback");
229: }
230: extTx.setRollbackOnly();
231: }
232: } catch (Exception ignore) {
233: }
234: txRepository.set(null);
235: }
236:
237: public void configure(Configuration config) {
238: /**
239: * no-op
240: */
241: }
242:
243: //************************************************************************
244: // inner class
245: //************************************************************************
246: private static final class TxBuffer {
247: private WeakReference externTx = null;
248: private WeakReference internTx = null;
249:
250: public TxBuffer() {
251: }
252:
253: /*
254: arminw:
255: use WeakReference to make sure that closed Transaction objects can be
256: immediately reclaimed by the garbage collector.
257: */
258:
259: public TxBuffer(TransactionImpl internTx, Transaction externTx) {
260: this .internTx = new WeakReference(internTx);
261: this .externTx = new WeakReference(externTx);
262: }
263:
264: public Transaction getExternTx() {
265: return (Transaction) externTx.get();
266: }
267:
268: public void setExternTx(Transaction externTx) {
269: this .externTx = new WeakReference(externTx);
270: }
271:
272: public TransactionImpl getInternTx() {
273: return (TransactionImpl) internTx.get();
274: }
275:
276: public void setInternTx(TransactionImpl internTx) {
277: this .internTx = new WeakReference(internTx);
278: }
279: }
280: }
|