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