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;
051:
052: import java.util.Collection;
053: import org.jaffa.persistence.exceptions.*;
054: import org.jaffa.persistence.engines.IPersistenceEngine;
055: import org.jaffa.persistence.engines.PersistenceEngineFactory;
056:
057: /**
058: * The UOW (Unit of Work) is the application developers interface to the persistence layer.
059: * Through this all writes, updates and deletes are executed.
060: * The UOW also provides the querying mechanism against the persistent store.
061: */
062: public class UOW {
063:
064: private boolean m_inactive = false;
065: private IPersistenceEngine m_engine = null;
066:
067: /** Creates new UOW. A connection is established with the underlying persistence store.
068: * @throws UOWException if any error occurs during the process.
069: */
070: public UOW() throws UOWException {
071: m_engine = PersistenceEngineFactory.newInstance();
072: }
073:
074: /** Generates an appropriate instance for the input persistentClass.
075: * If the persistentClass is a 'Class', then it should implement the 'IPersistent' interface. The persistence engine will simply instantiate the class.
076: * If the persistentClass is an 'Interface', then the persistence engine will generate a dynamic proxy, to implement the IPersistent and the 'persistentClass' interfaces.
077: * @param persistentClass The actual persistentClass which can represent a 'Class' or an 'Interface'
078: * @return an instance implementing the IPersistent interface.
079: */
080: public IPersistent newPersistentInstance(Class persistentClass) {
081: return m_engine.newPersistentInstance(persistentClass);
082: }
083:
084: /** This is a helper method to determine the actual class which was used to create an IPersistent instance.
085: * It is quite possible that the input object is a dynamic proxy.
086: * @param object The object which implements the IPersistent instance.
087: * @return The class which was used for instantiating the instance.
088: */
089: public Class getActualPersistentClass(Object persistentObject) {
090: return m_engine.getActualPersistentClass(persistentObject);
091: }
092:
093: /**
094: * Adds an object to the UOW for addition to the persistent store.
095: * The persistence engine may choose to add the object(s) only on a <code>commit</code>.
096: * @param object The object to persist. It should implement the IPersistent interface.
097: * @throws AddFailedException if any error occurs during the process.
098: */
099: public void add(Object object) throws AddFailedException {
100: IPersistent persistentObject = (IPersistent) object;
101: ensureActiveState();
102: preAddChecks(persistentObject);
103: persistentObject.setUOW(this );
104: m_engine.add(persistentObject);
105: }
106:
107: /**
108: * Adds an object to the UOW for updation to the persistent store.
109: * The persistence engine may choose to update the object(s) only on a <code>commit</code>.
110: * @param object The object to update. It should implement the IPersistent interface.
111: * @throws UpdateFailedException if any error occurs during the process.
112: */
113: public void update(Object object) throws UpdateFailedException {
114: IPersistent persistentObject = (IPersistent) object;
115: ensureActiveState();
116: preUpdateChecks(persistentObject);
117: m_engine.update(persistentObject);
118: }
119:
120: /**
121: * Adds an object to the UOW for deletion from the persistent store.
122: * The persistence engine may choose to delete the object(s) only on a <code>commit</code>.
123: * @param object The object to delete from persistent storage. It should implement the IPersistent interface.
124: * @throws DeleteFailedException if any error occurs during the process.
125: */
126: public void delete(Object object) throws DeleteFailedException {
127: IPersistent persistentObject = (IPersistent) object;
128: ensureActiveState();
129: preDeleteChecks(persistentObject);
130: m_engine.delete(persistentObject);
131: }
132:
133: /**
134: * Queries the underlying persistent store based on the search profile passed in the {@link Criteria} object.
135: * @param criteria search profile for the query.
136: * @return a Collection of persistent objects.
137: * @throws QueryFailedException if any error occurs during the process.
138: * @throws PostLoadFailedException if any error occurs during the invocation of the PostLoad trigger on the persistent object.
139: */
140: public Collection query(Criteria criteria)
141: throws QueryFailedException, PostLoadFailedException {
142: ensureActiveState();
143: criteria.setUow(this );
144: return m_engine.query(criteria);
145: }
146:
147: /**
148: * Objects that have been added, objects that have been deleted,
149: * and objects that have been updated, will all be persisted via
150: * an invocation of this method.
151: * Note: After a successful commit, this object will free up its connection to the database,
152: * and will no longer be available.
153: * @throws AddFailedException if any error occurs during the addition of objects to the persistent store.
154: * @throws UpdateFailedException if any error occurs while updating the objects of the persistent store.
155: * @throws DeleteFailedException if any error occurs while deleting the objects of the persistent store.
156: * @throws CommitFailedException if any error occurs during the commit.
157: */
158: public void commit() throws AddFailedException,
159: UpdateFailedException, DeleteFailedException,
160: CommitFailedException {
161: ensureActiveState();
162: m_engine.commit();
163: close();
164: }
165:
166: /**
167: * Rollbacks all the additions, deletions, updations.
168: * Note: This object will free up its connection to the database, and will no longer be available.
169: * @throws RollbackFailedException if any error occurs during the process.
170: */
171: public void rollback() throws RollbackFailedException {
172: if (isActive()) {
173: m_engine.rollback();
174: close();
175: }
176: }
177:
178: /**
179: * This will acquire a lock on the database row corrsponding to the input persistent object.
180: * @param object The persistent object to be locked. It should implement the IPersistent interface.
181: * @throws AlreadyLockedObjectException if the database row has been locked by another process.
182: */
183: public void acquireLock(Object object)
184: throws AlreadyLockedObjectException {
185: IPersistent persistentObject = (IPersistent) object;
186: ensureActiveState();
187: preAcquireLockChecks(persistentObject);
188: m_engine.acquireLock(persistentObject);
189: }
190:
191: /** Returns true if the UOW is active. The UOW becomes inactive after a commit or a rollback.
192: * @return true if the UOW is active.
193: */
194: public boolean isActive() {
195: return !m_inactive;
196: }
197:
198: /** This invokes the rollback() method, which will rollback & close the connection(if still open).
199: * @throws Throwable if any error occurs.
200: */
201: protected void finalize() throws Throwable {
202: rollback();
203: super .finalize();
204: }
205:
206: /** Throws an InactiveUowRuntimeException if the UOW is inactive */
207: private void ensureActiveState() throws InactiveUowRuntimeException {
208: if (!isActive())
209: throw new InactiveUowRuntimeException();
210: }
211:
212: /** Closes the connection and marks the UOW as inactive */
213: private void close() {
214: if (m_engine != null) {
215: m_engine.close();
216: m_engine = null;
217: }
218: m_inactive = true;
219: }
220:
221: private void preAddChecks(IPersistent object) {
222: if (object.getUOW() != null && object.getUOW() != this )
223: throw new InvalidUowRuntimeException();
224: if (object.isDatabaseOccurence())
225: throw new IllegalArgumentException(
226: "Cannot add an object, which already exists in the database.");
227: }
228:
229: private void preUpdateChecks(IPersistent object) {
230: if (object.getUOW() != this )
231: throw new InvalidUowRuntimeException();
232: if (!object.isDatabaseOccurence())
233: throw new IllegalArgumentException(
234: "Cannot update an object, which is not already in the database.");
235: }
236:
237: private void preDeleteChecks(IPersistent object) {
238: if (object.getUOW() != this )
239: throw new InvalidUowRuntimeException();
240: if (!object.isDatabaseOccurence())
241: throw new IllegalArgumentException(
242: "Cannot delete an object, which is not already in the database.");
243: }
244:
245: private void preAcquireLockChecks(IPersistent object) {
246: if (object.getUOW() != this )
247: throw new InvalidUowRuntimeException();
248: if (!object.isDatabaseOccurence())
249: throw new IllegalArgumentException(
250: "Cannot lock an object, which is not already in the database.");
251: }
252:
253: }
|