KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > DataRowUtils


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.access;
58
59 import java.util.Iterator JavaDoc;
60 import java.util.Map JavaDoc;
61
62 import org.objectstyle.cayenne.DataObject;
63 import org.objectstyle.cayenne.DataRow;
64 import org.objectstyle.cayenne.Fault;
65 import org.objectstyle.cayenne.ObjectId;
66 import org.objectstyle.cayenne.PersistenceState;
67 import org.objectstyle.cayenne.conf.Configuration;
68 import org.objectstyle.cayenne.map.DbJoin;
69 import org.objectstyle.cayenne.map.DbRelationship;
70 import org.objectstyle.cayenne.map.ObjAttribute;
71 import org.objectstyle.cayenne.map.ObjEntity;
72 import org.objectstyle.cayenne.map.ObjRelationship;
73 import org.objectstyle.cayenne.util.Util;
74
75 /**
76  * DataRowUtils contains a number of static methods to work with DataRows. This
77  * is a helper class for DataContext and ObjectStore
78  *
79  * @author Andrei Adamchik
80  * @since 1.1
81  */

82 class DataRowUtils {
83
84     /**
85      * Replaces all object attribute values with snapshot values. Sets object
86      * state to COMMITTED, unless the snapshot is partial in which case the
87      * state is set to HOLLOW
88      */

89     static void refreshObjectWithSnapshot(
90         ObjEntity objEntity,
91         DataObject object,
92         DataRow snapshot,
93         boolean invalidateToManyRelationships) {
94
95         Map JavaDoc attrMap = objEntity.getAttributeMap();
96         Iterator JavaDoc it = attrMap.keySet().iterator();
97         boolean isPartialSnapshot = false;
98         while (it.hasNext()) {
99             String JavaDoc attrName = (String JavaDoc) it.next();
100             ObjAttribute attr = (ObjAttribute) attrMap.get(attrName);
101             String JavaDoc dbAttrPath = attr.getDbAttributePath();
102             object.writePropertyDirectly(attrName, snapshot.get(dbAttrPath));
103             if (!snapshot.containsKey(dbAttrPath)) {
104                 //Note the distinction between
105
// 1) the map returning null because there was no mapping
106
// for that key and
107
// 2) returning null because 'null' was the value mapped
108
// for that key.
109
// If the first case (this clause) then snapshot is only
110
// partial
111
isPartialSnapshot = true;
112             }
113         }
114
115         Iterator JavaDoc rit = objEntity.getRelationships().iterator();
116         while (rit.hasNext()) {
117             ObjRelationship rel = (ObjRelationship) rit.next();
118             if (rel.isToMany()) {
119
120                 // "to many" relationships have no information to collect from
121
// snapshot
122
// initialize a new empty list if requested, but otherwise
123
// ignore snapshot data
124

125                 Object JavaDoc toManyList = object.readPropertyDirectly(rel.getName());
126
127                 if (toManyList == null) {
128                     object.writePropertyDirectly(rel.getName(), Fault.getToManyFault());
129                 }
130                 else if (
131                     invalidateToManyRelationships && toManyList instanceof ToManyList) {
132                     ((ToManyList) toManyList).invalidateObjectList();
133                 }
134
135                 continue;
136             }
137
138             // set a shared fault to indicate any kind of unresolved to-one
139
object.writePropertyDirectly(rel.getName(), Fault.getToOneFault());
140         }
141
142         if (isPartialSnapshot) {
143             object.setPersistenceState(PersistenceState.HOLLOW);
144         }
145         else {
146             object.setPersistenceState(PersistenceState.COMMITTED);
147             object.setSnapshotVersion(snapshot.getVersion());
148         }
149
150     }
151
152     static void forceMergeWithSnapshot(
153         ObjEntity entity,
154         DataObject anObject,
155         DataRow snapshot) {
156
157         DataContext context = anObject.getDataContext();
158         Map JavaDoc oldSnap =
159             context.getObjectStore().getSnapshot(anObject.getObjectId(), context);
160
161         // attributes
162
Map JavaDoc attrMap = entity.getAttributeMap();
163         Iterator JavaDoc it = attrMap.keySet().iterator();
164         while (it.hasNext()) {
165             String JavaDoc attrName = (String JavaDoc) it.next();
166             ObjAttribute attr = (ObjAttribute) attrMap.get(attrName);
167
168             //processing compound attributes correctly
169
String JavaDoc dbAttrPath = attr.getDbAttributePath();
170
171             // supports merging of partial snapshots...
172
// check for null is cheaper than double lookup
173
// for a key... so check for partial snapshot
174
// only if the value is null
175
Object JavaDoc newVal = snapshot.get(dbAttrPath);
176             if (newVal == null && !snapshot.containsKey(dbAttrPath)) {
177                 continue;
178             }
179
180             Object JavaDoc curVal = anObject.readPropertyDirectly(attrName);
181             Object JavaDoc oldVal = oldSnap.get(dbAttrPath);
182
183             // if value not modified, update it from snapshot,
184
// otherwise leave it alone
185
if (Util.nullSafeEquals(curVal, oldVal)
186                 && !Util.nullSafeEquals(newVal, curVal)) {
187                 anObject.writePropertyDirectly(attrName, newVal);
188             }
189         }
190
191         // merge to-one relationships
192
Iterator JavaDoc rit = entity.getRelationships().iterator();
193         while (rit.hasNext()) {
194             ObjRelationship rel = (ObjRelationship) rit.next();
195             if (rel.isToMany()) {
196                 continue;
197             }
198
199             // TODO: will this work for flattened, how do we save snapshots for
200
// them?
201

202             // if value not modified, update it from snapshot,
203
// otherwise leave it alone
204
if (!isToOneTargetModified(rel, anObject, oldSnap)
205                 && isJoinAttributesModified(rel, snapshot, oldSnap)) {
206
207                 DbRelationship dbRelationship =
208                     (DbRelationship) rel.getDbRelationships().get(0);
209
210                 ObjectId id =
211                     snapshot.createTargetObjectId(
212                         ((ObjEntity) rel.getTargetEntity()).getJavaClass(
213                             Configuration.getResourceLoader()),
214                         dbRelationship);
215                 DataObject target = (id != null) ? context.registeredObject(id) : null;
216
217                 anObject.writePropertyDirectly(rel.getName(), target);
218             }
219         }
220     }
221
222     /**
223      * Merges changes reflected in snapshot map to the object. Changes made to
224      * attributes and to-one relationships will be merged. In case an object is
225      * already modified, modified properties will not be overwritten.
226      */

227     static void mergeObjectWithSnapshot(
228         ObjEntity entity,
229         DataObject anObject,
230         Map JavaDoc snapshot) {
231
232         // TODO: once we use DataRow consistently instead of a Map, this line
233
// should go away.
234
// Instead method signiture should include "DataRow".
235
DataRow dataRow =
236             (snapshot instanceof DataRow) ? (DataRow) snapshot : new DataRow(snapshot);
237
238         if (entity.isReadOnly()
239             || anObject.getPersistenceState() == PersistenceState.HOLLOW) {
240             refreshObjectWithSnapshot(entity, anObject, dataRow, true);
241         }
242         else if (anObject.getPersistenceState() == PersistenceState.COMMITTED) {
243             // do not invalidate to-many relationships, since they might have
244
// just been prefetched...
245
refreshObjectWithSnapshot(entity, anObject, dataRow, false);
246         }
247         else {
248             forceMergeWithSnapshot(entity, anObject, dataRow);
249         }
250     }
251
252     /**
253      * Checks if a new snapshot has a modified to-one relationship compared to
254      * the cached snapshot.
255      */

256     static boolean isJoinAttributesModified(
257         ObjRelationship relationship,
258         Map JavaDoc newSnapshot,
259         Map JavaDoc storedSnapshot) {
260
261         Iterator JavaDoc it =
262             ((DbRelationship) relationship.getDbRelationships().get(0))
263                 .getJoins()
264                 .iterator();
265         while (it.hasNext()) {
266             DbJoin join = (DbJoin) it.next();
267             String JavaDoc propertyName = join.getSourceName();
268
269             // for equality to be true, snapshot must contain all matching pk
270
// values
271
if (!Util
272                 .nullSafeEquals(
273                     newSnapshot.get(propertyName),
274                     storedSnapshot.get(propertyName))) {
275                 return true;
276             }
277         }
278
279         return false;
280     }
281
282     /**
283      * Checks if an object has its to-one relationship target modified in
284      * memory.
285      */

286     static boolean isToOneTargetModified(
287         ObjRelationship relationship,
288         DataObject object,
289         Map JavaDoc storedSnapshot) {
290
291         if (object.getPersistenceState() != PersistenceState.MODIFIED) {
292             return false;
293         }
294
295         Object JavaDoc targetObject = object.readPropertyDirectly(relationship.getName());
296         if (targetObject instanceof Fault) {
297             return false;
298         }
299
300         DataObject toOneTarget = (DataObject) targetObject;
301         ObjectId currentId = (toOneTarget != null) ? toOneTarget.getObjectId() : null;
302
303         // if ObjectId is temporary, target is definitely modified...
304
// this would cover NEW objects (what are the other cases of temp id??)
305
if (currentId != null && currentId.isTemporary()) {
306             return true;
307         }
308
309         // check if ObjectId map is a subset of a stored snapshot;
310
// this is an equality condition
311
Iterator JavaDoc it =
312             ((DbRelationship) relationship.getDbRelationships().get(0))
313                 .getJoins()
314                 .iterator();
315
316         while (it.hasNext()) {
317             DbJoin join = (DbJoin) it.next();
318             String JavaDoc propertyName = join.getSourceName();
319
320             if (currentId == null) {
321                 // for equality to be true, snapshot must contain no pk values
322
if (storedSnapshot.get(propertyName) != null) {
323                     return true;
324                 }
325             }
326             else {
327                 // for equality to be true, snapshot must contain all matching
328
// pk values
329
// note that we must use target entity names to extract id
330
// values.
331
if (!Util
332                     .nullSafeEquals(
333                         currentId.getValueForAttribute(join.getTarget().getName()),
334                         storedSnapshot.get(propertyName))) {
335                     return true;
336                 }
337             }
338         }
339
340         return false;
341     }
342
343     /**
344      * Instantiation is not allowed.
345      */

346     DataRowUtils() {
347         super();
348     }
349 }
350
Popular Tags