001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049:
050: package org.jaffa.persistence.engines.jdbcengine.datasource;
051:
052: import org.apache.log4j.Logger;
053: import java.util.*;
054: import java.sql.SQLException;
055: import org.jaffa.persistence.Criteria;
056: import org.jaffa.persistence.IPersistent;
057: import org.jaffa.persistence.engines.jdbcengine.datasource.exceptions.DataSourceCreationException;
058: import org.jaffa.persistence.exceptions.IllegalPersistentStateRuntimeException;
059: import org.jaffa.persistence.exceptions.AddFailedException;
060: import org.jaffa.persistence.exceptions.UpdateFailedException;
061: import org.jaffa.persistence.exceptions.DeleteFailedException;
062: import org.jaffa.rules.RulesEngine;
063: import org.jaffa.persistence.engines.jdbcengine.configservice.initdomain.Database;
064:
065: /** This class is used to hold a connection to the database. It holds collections of objects to be added, updated, deleted or queried.
066: * The UOW will add objects to these collections. The JdbcBridge will utilise the collections to perform the relevant operations.
067: * It is important to invoke the close() method, which will free up the pooled connection.
068: */
069: public class PersistentTransaction {
070: private static final Logger log = Logger
071: .getLogger(PersistentTransaction.class);
072:
073: private DataSource m_dataSource;
074: private Collection m_adds;
075: private Collection m_updates;
076: private Collection m_deletes;
077: private Collection m_queries;
078:
079: /** Creates a PersitentTransaction. It uses the input Database configuration to acquire a Connection to the database.
080: * @param database The object with the requisite information for acquiring a Connection to the database.
081: * @throws DataSourceCreationException if the connection could not be acquired.
082: */
083: public PersistentTransaction(Database database)
084: throws DataSourceCreationException {
085: if (log.isDebugEnabled())
086: log.debug("Acquiring a new DataSource");
087: m_dataSource = DataSourceFactory.getDataSource(database);
088: }
089:
090: /** Adds an object to the transaction to be written.
091: * The PreAdd trigger for will be invoked and the domain object will be validated before the addition to the transaction.
092: * @param object the object to be created.
093: * @throws AddFailedException if any error occurs during the validation of the persistent object.
094: * @throws IllegalPersistentStateRuntimeException this RuntimeException will be thrown if the domain object has been submitted to the UOW for an Add/Update/Delete and commit hasnt yet been performed.
095: */
096: public void addObject(IPersistent object)
097: throws AddFailedException,
098: IllegalPersistentStateRuntimeException {
099: if (object.isQueued()) {
100: String str = "The domain object has already been submitted to the UOW for an Add/Update/Delete. No more updates can be performed until after a commit";
101: log.error(str);
102: throw new IllegalPersistentStateRuntimeException(str);
103: }
104:
105: if (log.isDebugEnabled())
106: log
107: .debug("Invoking the PreAdd trigger on the Persistent object");
108: object.preAdd();
109:
110: if (m_adds == null)
111: m_adds = new ArrayList();
112: m_adds.add(object);
113: if (log.isDebugEnabled())
114: log
115: .debug("Added the Persistent object to the ADD collection");
116:
117: object.setQueued(true);
118:
119: if (log.isDebugEnabled())
120: log
121: .debug("Invoking the PostAdd trigger on the Persistent object");
122: object.postAdd();
123: }
124:
125: /** Adds an object to the transaction to be updated.
126: * The PreUpdate trigger will be invoked and the domain object will be validated before the updation to the transaction.
127: * @param object the object to be updated.
128: * @throws UpdateFailedException if any error occurs during the validation of the persistent object.
129: * @throws IllegalPersistentStateRuntimeException this RuntimeException will be thrown if the domain object has been submitted to the UOW for an Add/Update/Delete and commit hasnt yet been performed.
130: */
131: public void updateObject(IPersistent object)
132: throws UpdateFailedException,
133: IllegalPersistentStateRuntimeException {
134: if (object.isQueued()) {
135: String str = "The domain object has already been submitted to the UOW for an Add/Update/Delete. No more updates can be performed until after a commit";
136: log.error(str);
137: throw new IllegalPersistentStateRuntimeException(str);
138: }
139:
140: if (!object.isModified()) {
141: if (log.isDebugEnabled())
142: log
143: .debug("The Persistent object has not been modified. So it will not be added to the Interceptor queue for an Add");
144: return;
145: }
146:
147: if (log.isDebugEnabled())
148: log
149: .debug("Invoking the PreUpdate trigger on the Persistent object");
150: object.preUpdate();
151:
152: if (m_updates == null)
153: m_updates = new ArrayList();
154: m_updates.add(object);
155: if (log.isDebugEnabled())
156: log
157: .debug("Added the Persistent object to the UPDATE collection");
158:
159: object.setQueued(true);
160:
161: if (log.isDebugEnabled())
162: log
163: .debug("Invoking the PostUpdate trigger on the Persistent object");
164: object.postUpdate();
165: }
166:
167: /** Adds an object to the transaction to be deleted.
168: * The PreDelete trigger will be invoked before the deletion from the transaction.
169: * @param object the object to be deleted.
170: * @throws DeleteFailedException if any error occurs during the process.
171: * @throws IllegalPersistentStateRuntimeException this RuntimeException will be thrown if the domain object has been submitted to the UOW for an Add/Update/Delete and commit hasnt yet been performed.
172: */
173: public void deleteObject(IPersistent object)
174: throws DeleteFailedException,
175: IllegalPersistentStateRuntimeException {
176: if (object.isQueued()) {
177: String str = "The domain object has already been submitted to the UOW for an Add/Update/Delete. No more updates can be performed until after a commit";
178: log.error(str);
179: throw new IllegalPersistentStateRuntimeException(str);
180: }
181:
182: if (log.isDebugEnabled())
183: log
184: .debug("Invoking the PreDelete trigger on the Persistent object");
185: object.preDelete();
186:
187: if (m_deletes == null)
188: m_deletes = new ArrayList();
189: m_deletes.add(object);
190: if (log.isDebugEnabled())
191: log
192: .debug("Added the Persistent object to the DELETE collection");
193:
194: object.setQueued(true);
195:
196: if (log.isDebugEnabled())
197: log
198: .debug("Invoking the PostDelete trigger on the Persistent object");
199: object.postDelete();
200: }
201:
202: /** Adds a Criteria object to the transaction for performing a query.
203: * @param object the Criteria based on which a query is to be performed.
204: */
205: public void queryObject(Criteria object) {
206: if (m_queries == null)
207: m_queries = new ArrayList();
208: m_queries.add(object);
209: if (log.isDebugEnabled())
210: log
211: .debug("Added the Persistent object to the QUERY collection");
212: }
213:
214: /** Commits all changes executed against the persistent store.
215: * @throws SQLException if any database error occurs.
216: */
217: public void commit() throws SQLException {
218: if (log.isDebugEnabled())
219: log.debug("Invoking the commit on the DataSource");
220: m_dataSource.commit();
221: clearCollections();
222: }
223:
224: /** Rollback the changes executed against the persistent store.
225: * @throws SQLException if any database error occurs.
226: */
227: public void rollback() throws SQLException {
228: if (log.isDebugEnabled())
229: log.debug("Invoking the rollback on the DataSource");
230: m_dataSource.rollback();
231: clearCollections();
232: }
233:
234: /** This will free up the underlying pooled connection. It will first do an implicit rollback().
235: * @throws SQLException if any database error occurs.
236: */
237: public void close() throws SQLException {
238: if (log.isDebugEnabled())
239: log.debug("Invoking the rollback on the DataSource");
240: rollback();
241:
242: if (log.isDebugEnabled())
243: log.debug("Freeing up the DataSource");
244: DataSourceFactory.freeDataSource(m_dataSource);
245: m_dataSource = null;
246: }
247:
248: /** Returns the DataSource holding the Connection.
249: * @return the DataSource.
250: */
251: public DataSource getDataSource() {
252: return m_dataSource;
253: }
254:
255: /** Returns a Collection of Persistent objects to be added to the persistent store.
256: * @return a Collection of objects to be added.
257: */
258: public Collection getAdds() {
259: return m_adds;
260: }
261:
262: /** Returns a Collection of Persistent objects to be updated in the persistent store.
263: * @return a Collection of objects to be updated.
264: */
265: public Collection getUpdates() {
266: return m_updates;
267: }
268:
269: /** Returns a Collection of Persistent objects to be deleted from the persistent store.
270: * @return a Collection of objects to be deleted.
271: */
272: public Collection getDeletes() {
273: return m_deletes;
274: }
275:
276: /** Returns a Collection of Criteria objects to be used for querying the persistent store.
277: * @return a Collection of Criteria objects to be used for queries.
278: */
279: public Collection getQueries() {
280: return m_queries;
281: }
282:
283: private void clearCollections() {
284: if (log.isDebugEnabled())
285: log
286: .debug("Clearing up all the internal collections for the added, updated, deleted and query objects");
287: if (m_adds != null)
288: m_adds.clear();
289: if (m_updates != null)
290: m_updates.clear();
291: if (m_deletes != null)
292: m_deletes.clear();
293: if (m_queries != null)
294: m_queries.clear();
295: }
296:
297: }
|