KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.access;
21
22 import org.apache.cayenne.DataRow;
23 import org.apache.cayenne.ObjectId;
24 import org.apache.cayenne.PersistenceState;
25 import org.apache.cayenne.Persistent;
26 import org.apache.cayenne.map.DbRelationship;
27 import org.apache.cayenne.map.ObjAttribute;
28 import org.apache.cayenne.map.ObjEntity;
29 import org.apache.cayenne.map.ObjRelationship;
30 import org.apache.cayenne.reflect.ArcProperty;
31 import org.apache.cayenne.reflect.AttributeProperty;
32 import org.apache.cayenne.reflect.ClassDescriptor;
33 import org.apache.cayenne.reflect.PropertyVisitor;
34 import org.apache.cayenne.reflect.ToManyProperty;
35 import org.apache.cayenne.reflect.ToOneProperty;
36 import org.apache.cayenne.util.Util;
37
38 /**
39  * DataRowUtils contains a number of static methods to work with DataRows. This is a
40  * helper class for DataContext and ObjectStore.
41  *
42  * @author Andrus Adamchik
43  * @since 1.1
44  */

45 class DataRowUtils {
46
47     /**
48      * Merges changes reflected in snapshot map to the object. Changes made to attributes
49      * and to-one relationships will be merged. In case an object is already modified,
50      * modified properties will not be overwritten.
51      */

52     static void mergeObjectWithSnapshot(
53             DataContext context,
54             ClassDescriptor descriptor,
55             Persistent object,
56             DataRow snapshot) {
57
58         int state = object.getPersistenceState();
59
60         if (state == PersistenceState.HOLLOW || descriptor.getEntity().isReadOnly()) {
61             refreshObjectWithSnapshot(descriptor, object, snapshot, true);
62         }
63         else if (state != PersistenceState.COMMITTED) {
64             forceMergeWithSnapshot(context, descriptor, object, snapshot);
65         }
66         else {
67             // do not invalidate to-many relationships, since they might have
68
// just been prefetched...
69
refreshObjectWithSnapshot(descriptor, object, snapshot, false);
70         }
71     }
72
73     /**
74      * Replaces all object attribute values with snapshot values. Sets object state to
75      * COMMITTED, unless the snapshot is partial in which case the state is set to HOLLOW
76      */

77     static void refreshObjectWithSnapshot(
78             ClassDescriptor descriptor,
79             final Persistent object,
80             final DataRow snapshot,
81             final boolean invalidateToManyRelationships) {
82
83         final boolean[] isPartialSnapshot = new boolean[1];
84
85         descriptor.visitProperties(new PropertyVisitor() {
86
87             public boolean visitAttribute(AttributeProperty property) {
88                 ObjAttribute attr = property.getAttribute();
89                 String JavaDoc dbAttrPath = attr.getDbAttributePath();
90
91                 Object JavaDoc value = snapshot.get(dbAttrPath);
92                 property.writePropertyDirectly(object, null, value);
93
94                 // note that a check "snaphsot.get(..) == null" would be incorrect in this
95
// case, as NULL value is entirely valid; still save a map lookup by
96
// checking for the null value first
97
if (value == null && !snapshot.containsKey(dbAttrPath)) {
98                     isPartialSnapshot[0] = true;
99                 }
100                 return true;
101             }
102
103             public boolean visitToMany(ToManyProperty property) {
104                 // "to many" relationships have no information to collect from
105
// snapshot
106
if (invalidateToManyRelationships) {
107                     property.invalidate(object);
108                 }
109
110                 return true;
111             }
112
113             public boolean visitToOne(ToOneProperty property) {
114                 property.invalidate(object);
115                 return true;
116             }
117         });
118
119         object.setPersistenceState(isPartialSnapshot[0]
120                 ? PersistenceState.HOLLOW
121                 : PersistenceState.COMMITTED);
122     }
123
124     static void forceMergeWithSnapshot(
125             final DataContext context,
126             ClassDescriptor descriptor,
127             final Persistent object,
128             final DataRow snapshot) {
129
130         final ObjectDiff diff = (ObjectDiff) context
131                 .getObjectStore()
132                 .getChangesByObjectId()
133                 .get(object.getObjectId());
134
135         descriptor.visitProperties(new PropertyVisitor() {
136
137             public boolean visitAttribute(AttributeProperty property) {
138                 String JavaDoc dbAttrPath = property.getAttribute().getDbAttributePath();
139
140                 // supports merging of partial snapshots...
141
// check for null is cheaper than double lookup
142
// for a key... so check for partial snapshot
143
// only if the value is null
144
Object JavaDoc newValue = snapshot.get(dbAttrPath);
145                 if (newValue != null || snapshot.containsKey(dbAttrPath)) {
146
147                     Object JavaDoc curValue = property.readPropertyDirectly(object);
148                     Object JavaDoc oldValue = diff != null ? diff.getSnapshotValue(property
149                             .getName()) : null;
150
151                     // if value not modified, update it from snapshot,
152
// otherwise leave it alone
153
if (Util.nullSafeEquals(curValue, oldValue)
154                             && !Util.nullSafeEquals(newValue, curValue)) {
155                         property.writePropertyDirectly(object, oldValue, newValue);
156                     }
157                 }
158                 return true;
159             }
160
161             public boolean visitToMany(ToManyProperty property) {
162                 // noop - nothing to merge
163
return true;
164             }
165
166             public boolean visitToOne(ToOneProperty property) {
167                 ObjRelationship relationship = property.getRelationship();
168                 if (relationship.isToPK()) {
169                     // TODO: will this work for flattened, how do we save snapshots for
170
// them?
171

172                     // if value not modified, update it from snapshot,
173
// otherwise leave it alone
174
if (!isToOneTargetModified(property, object, diff)) {
175
176                         DbRelationship dbRelationship = (DbRelationship) relationship
177                                 .getDbRelationships()
178                                 .get(0);
179
180                         ObjectId id = snapshot.createTargetObjectId(relationship
181                                 .getTargetEntityName(), dbRelationship);
182
183                         if (diff == null
184                                 || !diff.containsArcSnapshot(relationship.getName())
185                                 || !Util.nullSafeEquals(id, diff
186                                         .getArcSnapshotValue(relationship.getName()))) {
187
188                             if (id == null) {
189                                 property.writeProperty(object, null, null);
190                             }
191                             else {
192                                 // if inheritance is involved, we can't use 'localObject'
193
// .. must turn to fault instead
194
ObjEntity targetEntity = (ObjEntity) relationship
195                                         .getTargetEntity();
196                                 if (context.getEntityResolver().lookupInheritanceTree(
197                                         targetEntity) != null) {
198                                     property.invalidate(object);
199                                 }
200                                 else {
201                                     property.writeProperty(object, null, context
202                                             .localObject(id, null));
203                                 }
204                             }
205                         }
206                     }
207                 }
208                 return true;
209             }
210         });
211     }
212
213     /**
214      * Checks if an object has its to-one relationship target modified in memory.
215      */

216     static boolean isToOneTargetModified(
217             ArcProperty property,
218             Persistent object,
219             ObjectDiff diff) {
220
221         if (object.getPersistenceState() != PersistenceState.MODIFIED || diff == null) {
222             return false;
223         }
224
225         if (property.isFault(object)) {
226             return false;
227         }
228
229         Persistent toOneTarget = (Persistent) property.readPropertyDirectly(object);
230         ObjectId currentId = (toOneTarget != null) ? toOneTarget.getObjectId() : null;
231
232         // if ObjectId is temporary, target is definitely modified...
233
// this would cover NEW objects (what are the other cases of temp id??)
234
if (currentId != null && currentId.isTemporary()) {
235             return true;
236         }
237
238         if (!diff.containsArcSnapshot(property.getName())) {
239             return false;
240         }
241
242         ObjectId targetId = diff.getArcSnapshotValue(property.getName());
243         return !Util.nullSafeEquals(currentId, targetId);
244     }
245
246     // not for instantiation
247
DataRowUtils() {
248     }
249 }
250
Popular Tags