Source code: org/objectstyle/cayenne/access/util/ContextCommitObserver.java
1 /* ====================================================================
2 *
3 * The ObjectStyle Group Software License, Version 1.0
4 *
5 * Copyright (c) 2002-2003 The ObjectStyle Group
6 * and individual authors of the software. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution, if
21 * any, must include the following acknowlegement:
22 * "This product includes software developed by the
23 * ObjectStyle Group (http://objectstyle.org/)."
24 * Alternately, this acknowlegement may appear in the software itself,
25 * if and wherever such third-party acknowlegements normally appear.
26 *
27 * 4. The names "ObjectStyle Group" and "Cayenne"
28 * must not be used to endorse or promote products derived
29 * from this software without prior written permission. For written
30 * permission, please contact andrus@objectstyle.org.
31 *
32 * 5. Products derived from this software may not be called "ObjectStyle"
33 * nor may "ObjectStyle" appear in their names without prior written
34 * permission of the ObjectStyle Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the ObjectStyle Group. For more
52 * information on the ObjectStyle Group, please see
53 * <http://objectstyle.org/>.
54 *
55 */
56 package org.objectstyle.cayenne.access.util;
57
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.Iterator;
62 import java.util.List;
63 import java.util.Map;
64
65 import org.apache.log4j.Level;
66 import org.objectstyle.cayenne.CayenneRuntimeException;
67 import org.objectstyle.cayenne.DataObject;
68 import org.objectstyle.cayenne.ObjectId;
69 import org.objectstyle.cayenne.PersistenceState;
70 import org.objectstyle.cayenne.TempObjectId;
71 import org.objectstyle.cayenne.access.DataContext;
72 import org.objectstyle.cayenne.access.ObjectStore;
73 import org.objectstyle.cayenne.access.event.DataContextEvent;
74 import org.objectstyle.cayenne.access.event.DataContextTransactionEventListener;
75 import org.objectstyle.cayenne.access.event.DataObjectTransactionEventListener;
76 import org.objectstyle.cayenne.event.EventManager;
77 import org.objectstyle.cayenne.query.Query;
78 import org.objectstyle.cayenne.util.Util;
79
80 /**
81 * ContextCommitObserver is used as an observer for DataContext
82 * commit operations.
83 *
84 * @author Andrei Adamchik
85 */
86 public class ContextCommitObserver
87 extends DefaultOperationObserver
88 implements DataContextTransactionEventListener {
89
90 protected List updObjects;
91 protected List delObjects;
92 protected List insObjects;
93 protected List objectsToNotify;
94
95 protected DataContext context;
96
97 public ContextCommitObserver(
98 Level logLevel,
99 DataContext context,
100 List insObjects,
101 List updObjects,
102 List delObjects) {
103 super.setLoggingLevel(logLevel);
104 this.context = context;
105 this.insObjects = insObjects;
106 this.updObjects = updObjects;
107 this.delObjects = delObjects;
108 this.objectsToNotify = new ArrayList();
109
110 // Build a list of objects that need to be notified about posted
111 // DataContext events. When notifying about a successful completion
112 // of a transaction we cannot build this list anymore, since all
113 // the work will be done by then.
114 Iterator collIter =
115 (Arrays.asList(new List[] { delObjects, updObjects, insObjects }))
116 .iterator();
117 while (collIter.hasNext()) {
118 Iterator objIter = ((Collection) collIter.next()).iterator();
119 while (objIter.hasNext()) {
120 Object element = objIter.next();
121 if (element instanceof DataObjectTransactionEventListener) {
122 this.objectsToNotify.add(element);
123 }
124 }
125 }
126 }
127
128 public boolean useAutoCommit() {
129 return false;
130 }
131
132 /** Update the state of all objects we were synchronizing
133 * in this transaction.
134 */
135 public void transactionCommitted() {
136 super.transactionCommitted();
137
138 Iterator insIt = insObjects.iterator();
139 ObjectStore objectStore = context.getObjectStore();
140
141 synchronized (objectStore) {
142 while (insIt.hasNext()) {
143
144 // replace temp id's w/perm.
145 DataObject nextObject = (DataObject) insIt.next();
146 TempObjectId tempId = (TempObjectId) nextObject.getObjectId();
147 ObjectId permId = tempId.getPermId();
148
149 objectStore.changeObjectKey(tempId, permId);
150 nextObject.setObjectId(permId);
151 Map snapshot = context.takeObjectSnapshot(nextObject);
152 objectStore.addSnapshot(permId, snapshot);
153
154 nextObject.setPersistenceState(PersistenceState.COMMITTED);
155 }
156 }
157
158 Iterator delIt = delObjects.iterator();
159 while (delIt.hasNext()) {
160 DataObject nextObject = (DataObject) delIt.next();
161 ObjectId anId = nextObject.getObjectId();
162
163 objectStore.removeObject(anId);
164 nextObject.setPersistenceState(PersistenceState.TRANSIENT);
165 nextObject.setDataContext(null);
166 }
167
168 Iterator updIt = updObjects.iterator();
169 while (updIt.hasNext()) {
170 DataObject nextObject = (DataObject) updIt.next();
171 // refresh this object's snapshot, check if id data has changed
172 Map snapshot = context.takeObjectSnapshot(nextObject);
173
174 objectStore.addSnapshot(nextObject.getObjectId(), snapshot);
175 nextObject.setPersistenceState(PersistenceState.COMMITTED);
176 }
177 }
178
179 public void nextQueryException(Query query, Exception ex) {
180 super.nextQueryException(query, ex);
181 throw new CayenneRuntimeException(
182 "Raising from query exception.",
183 Util.unwindException(ex));
184 }
185
186 public void nextGlobalException(Exception ex) {
187 super.nextGlobalException(ex);
188 throw new CayenneRuntimeException(
189 "Raising from underlyingQueryEngine exception.",
190 Util.unwindException(ex));
191 }
192
193 public void registerForDataContextEvents() {
194 try {
195 EventManager mgr = EventManager.getDefaultManager();
196 mgr.addListener(
197 this,
198 "dataContextWillCommit",
199 DataContextEvent.class,
200 DataContext.WILL_COMMIT,
201 this.context);
202 mgr.addListener(
203 this,
204 "dataContextDidCommit",
205 DataContextEvent.class,
206 DataContext.DID_COMMIT,
207 this.context);
208 mgr.addListener(
209 this,
210 "dataContextDidRollback",
211 DataContextEvent.class,
212 DataContext.DID_ROLLBACK,
213 this.context);
214 } catch (NoSuchMethodException nsm) {
215 // this really should not happen since we implement all required methods
216 throw new CayenneRuntimeException(nsm);
217 }
218 }
219
220 public void unregisterFromDataContextEvents() {
221 EventManager mgr = EventManager.getDefaultManager();
222 mgr.removeListener(this, DataContext.WILL_COMMIT);
223 mgr.removeListener(this, DataContext.DID_COMMIT);
224 mgr.removeListener(this, DataContext.DID_ROLLBACK);
225 }
226
227 public void dataContextWillCommit(DataContextEvent event) {
228 Iterator iter = objectsToNotify.iterator();
229 while (iter.hasNext()) {
230 ((DataObjectTransactionEventListener) iter.next()).willCommit(
231 event);
232 }
233 }
234
235 public void dataContextDidCommit(DataContextEvent event) {
236 Iterator iter = objectsToNotify.iterator();
237 while (iter.hasNext()) {
238 ((DataObjectTransactionEventListener) iter.next()).didCommit(event);
239 }
240 }
241
242 public void dataContextDidRollback(DataContextEvent event) {
243 // do nothing for now
244 }
245 }