001: package org.apache.ojb.otm.core;
002:
003: /* Copyright 2003-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 java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021:
022: import org.apache.ojb.otm.OTMKit;
023: import org.apache.ojb.otm.OTMConnection;
024:
025: /**
026: * Transaction delivers the core function of OTMKit - to manage objects within the
027: * context of a transaction.
028: *
029: * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
030: */
031: public class Transaction {
032: private boolean _isInProgress;
033: private List _listeners;
034: private List _connections;
035: private OTMKit _kit;
036:
037: public Transaction() {
038: _listeners = new ArrayList();
039: _connections = new ArrayList();
040: }
041:
042: public OTMKit getKit() {
043: return _kit;
044: }
045:
046: public void setKit(OTMKit kit) {
047: _kit = kit;
048: }
049:
050: public void begin() throws TransactionException {
051: if (_isInProgress) {
052: throw new TransactionInProgressException(
053: "Transaction already in progress, cannot restart");
054: }
055:
056: _isInProgress = true;
057:
058: for (Iterator iterator = _connections.iterator(); iterator
059: .hasNext();) {
060: BaseConnection connection = (BaseConnection) iterator
061: .next();
062: connection.transactionBegin();
063: }
064:
065: for (Iterator iterator = _listeners.iterator(); iterator
066: .hasNext();) {
067: TransactionListener listener = (TransactionListener) iterator
068: .next();
069: listener.transactionBegan(this );
070: }
071: }
072:
073: /**
074: *
075: * Commit this transaction. A commit notifies all listeners of this transaction. It then
076: * initiates a two phase commit on connections. Since, connections cannot be associated to
077: * more than one transaction at any given point in time, there is no neccessity to identify
078: * transaction.
079: *
080: */
081: public void commit() throws TransactionException {
082: if (!_isInProgress) {
083: throw new TransactionNotInProgressException(
084: "Transaction not in progress, nothing to commit");
085: }
086:
087: for (Iterator iterator = _listeners.iterator(); iterator
088: .hasNext();) {
089: TransactionListener listener = (TransactionListener) iterator
090: .next();
091:
092: listener.transactionCommitting(this );
093: }
094:
095: for (Iterator iterator = _connections.iterator(); iterator
096: .hasNext();) {
097: BaseConnection connection = (BaseConnection) iterator
098: .next();
099: ConcreteEditingContext context = (ConcreteEditingContext) connection
100: .getEditingContext();
101:
102: context.commit();
103: connection.transactionPrepare();
104: }
105:
106: for (Iterator iterator = _connections.iterator(); iterator
107: .hasNext();) {
108: BaseConnection connection = (BaseConnection) iterator
109: .next();
110:
111: connection.transactionCommit();
112: connection.setTransaction(null);
113: }
114:
115: _connections.clear();
116: _isInProgress = false;
117: }
118:
119: /**
120: *
121: * Checkpoint this transaction.
122: *
123: */
124: public void checkpoint() throws TransactionException {
125: if (!_isInProgress) {
126: throw new TransactionNotInProgressException(
127: "Transaction not in progress, cannot checkpoint");
128: }
129:
130: for (Iterator iterator = _connections.iterator(); iterator
131: .hasNext();) {
132: BaseConnection connection = (BaseConnection) iterator
133: .next();
134: ConcreteEditingContext context = (ConcreteEditingContext) connection
135: .getEditingContext();
136:
137: context.checkpoint();
138: }
139: }
140:
141: /**
142: *
143: * Rollback this transaction. A rollback on the transaction, notifies all its listeners. It,
144: * then initiates a rollback on all associated connections.
145: *
146: */
147: public void rollback() throws TransactionException {
148: if (!_isInProgress) {
149: throw new TransactionNotInProgressException(
150: "Transaction not in progress, nothing to commit");
151: }
152:
153: for (Iterator iterator = _listeners.iterator(); iterator
154: .hasNext();) {
155: TransactionListener listener = (TransactionListener) iterator
156: .next();
157: listener.transactionRollingBack(this );
158: }
159:
160: for (Iterator iterator = _connections.iterator(); iterator
161: .hasNext();) {
162: BaseConnection connection = (BaseConnection) iterator
163: .next();
164: ConcreteEditingContext context = (ConcreteEditingContext) connection
165: .getEditingContext();
166:
167: context.rollback();
168: connection.transactionRollback();
169: connection.setTransaction(null);
170: }
171:
172: _connections.clear();
173: _isInProgress = false;
174: }
175:
176: public boolean isInProgress() {
177: return _isInProgress;
178: }
179:
180: /**
181: *
182: * Associate a connection to this transaction. A OTMConnection can be registered to atmost one
183: * transaction, while a transaction can manage multiple connections.
184: *
185: * @param connection the connection to register
186: *
187: */
188: public void registerConnection(OTMConnection connection) {
189: Transaction connectionTx = connection.getTransaction();
190: if ((connectionTx != null) && (connectionTx != this )) {
191: throw new TransactionException(
192: "Attempt to re-assign a different transaction to a open connection");
193: }
194:
195: if (!_connections.contains(connection)) {
196: _connections.add(connection);
197:
198: connection.setTransaction(this );
199:
200: }
201: }
202:
203: /**
204: *
205: * Adds a listener to this transaction. Listeners get boundary notifications of this
206: * transaction.
207: *
208: * @param listener the listener of this transaction
209: *
210: */
211: public void registerListener(TransactionListener listener) {
212: if (_listeners.indexOf(listener) < 0) {
213: _listeners.add(listener);
214: }
215: }
216: }
|