KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.Fault;
30 import org.apache.cayenne.ObjectId;
31 import org.apache.cayenne.PersistenceState;
32 import org.apache.cayenne.Persistent;
33 import org.apache.cayenne.graph.GraphChangeHandler;
34 import org.apache.cayenne.graph.GraphDiff;
35 import org.apache.cayenne.graph.NodeDiff;
36 import org.apache.cayenne.map.EntityResolver;
37 import org.apache.cayenne.map.ObjEntity;
38 import org.apache.cayenne.map.ObjRelationship;
39 import org.apache.cayenne.reflect.AttributeProperty;
40 import org.apache.cayenne.reflect.ClassDescriptor;
41 import org.apache.cayenne.reflect.Property;
42 import org.apache.cayenne.reflect.PropertyVisitor;
43 import org.apache.cayenne.reflect.ToManyProperty;
44 import org.apache.cayenne.reflect.ToOneProperty;
45 import org.apache.cayenne.util.Util;
46
47 /**
48  * A dynamic GraphDiff that represents a delta between object simple properties at diff
49  * creation time and its current state.
50  */

51 class ObjectDiff extends NodeDiff {
52
53     private final String JavaDoc entityName;
54
55     private transient ClassDescriptor classDescriptor;
56
57     private Collection JavaDoc otherDiffs;
58
59     private Map JavaDoc snapshot;
60     private Map JavaDoc arcSnapshot;
61     private Map JavaDoc currentArcSnapshot;
62     private Map JavaDoc flatIds;
63
64     private Persistent object;
65
66     ObjectDiff(final Persistent object) {
67
68         super(object.getObjectId());
69
70         // retain the object, as ObjectStore may have weak references to registered
71
// objects and we can't allow it to deallocate dirty objects.
72
this.object = object;
73
74         EntityResolver entityResolver = object.getObjectContext().getEntityResolver();
75
76         this.entityName = object.getObjectId().getEntityName();
77         this.classDescriptor = entityResolver.getClassDescriptor(entityName);
78
79         int state = object.getPersistenceState();
80
81         // take snapshot of simple properties and arcs used for optimistic locking..
82

83         if (state == PersistenceState.COMMITTED
84                 || state == PersistenceState.DELETED
85                 || state == PersistenceState.MODIFIED) {
86
87             ObjEntity entity = entityResolver.getObjEntity(entityName);
88             final boolean lock = entity.getLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC;
89
90             this.snapshot = new HashMap JavaDoc();
91             this.arcSnapshot = new HashMap JavaDoc();
92
93             classDescriptor.visitProperties(new PropertyVisitor() {
94
95                 public boolean visitAttribute(AttributeProperty property) {
96                     snapshot.put(property.getName(), property.readProperty(object));
97                     return true;
98                 }
99
100                 public boolean visitToMany(ToManyProperty property) {
101                     return true;
102                 }
103
104                 public boolean visitToOne(ToOneProperty property) {
105
106                     // eagerly resolve optimistically locked relationships
107
Object JavaDoc target = lock ? property.readProperty(object) : property
108                             .readPropertyDirectly(object);
109
110                     if (target instanceof Persistent) {
111                         target = ((Persistent) target).getObjectId();
112                     }
113                     // else - null || Fault
114

115                     arcSnapshot.put(property.getName(), target);
116                     return true;
117                 }
118             });
119         }
120     }
121     
122     Object JavaDoc getObject() {
123         return object;
124     }
125
126     ClassDescriptor getClassDescriptor() {
127         // class descriptor is initiated in constructor, but is nullified on serialization
128
if (classDescriptor == null) {
129             EntityResolver entityResolver = object.getObjectContext().getEntityResolver();
130             this.classDescriptor = entityResolver.getClassDescriptor(entityName);
131         }
132
133         return classDescriptor;
134     }
135
136     Object JavaDoc getSnapshotValue(String JavaDoc propertyName) {
137         return snapshot != null ? snapshot.get(propertyName) : null;
138     }
139
140     ObjectId getArcSnapshotValue(String JavaDoc propertyName) {
141         Object JavaDoc value = arcSnapshot != null ? arcSnapshot.get(propertyName) : null;
142
143         if (value instanceof Fault) {
144             Persistent target = (Persistent) ((Fault) value).resolveFault(
145                     object,
146                     propertyName);
147
148             value = target != null ? target.getObjectId() : null;
149             arcSnapshot.put(propertyName, value);
150         }
151
152         return (ObjectId) value;
153     }
154
155     boolean containsArcSnapshot(String JavaDoc propertyName) {
156         return arcSnapshot != null ? arcSnapshot.containsKey(propertyName) : false;
157     }
158
159     /**
160      * Appends individual diffs to collection.
161      */

162     void appendDiffs(Collection JavaDoc collection) {
163
164         if (otherDiffs != null) {
165             collection.addAll(otherDiffs);
166         }
167
168         collection.add(new NodeDiff(nodeId, diffId) {
169
170             public void apply(GraphChangeHandler tracker) {
171                 applySimplePropertyChanges(tracker);
172             }
173
174             public void undo(GraphChangeHandler tracker) {
175                 throw new UnsupportedOperationException JavaDoc();
176             }
177         });
178     }
179
180     void addDiff(GraphDiff diff) {
181
182         boolean addDiff = true;
183
184         if (diff instanceof ArcOperation && snapshot != null) {
185
186             ArcOperation arcDiff = (ArcOperation) diff;
187             Object JavaDoc targetId = arcDiff.getTargetNodeId();
188             String JavaDoc arcId = arcDiff.getArcId().toString();
189
190             Property property = getClassDescriptor().getProperty(arcId);
191
192             // note that some collection properties implement 'SingleObjectArcProperty',
193
// so we cant't do 'instanceof SingleObjectArcProperty'
194
// TODO: andrus, 3.22.2006 - should we consider this a bug?
195

196             if (property instanceof ToManyProperty) {
197
198                 // record flattened op changes
199
ObjEntity entity = object
200                         .getObjectContext()
201                         .getEntityResolver()
202                         .getObjEntity(entityName);
203
204                 ObjRelationship relationship = (ObjRelationship) entity
205                         .getRelationship(property.getName());
206                 if (relationship.isFlattened()) {
207
208                     if (flatIds == null) {
209                         flatIds = new HashMap JavaDoc();
210                     }
211
212                     ArcOperation oldOp = (ArcOperation) flatIds.put(arcDiff, arcDiff);
213
214                     // "delete" cancels "create" and vice versa...
215
if (oldOp != null && oldOp.isDelete() != arcDiff.isDelete()) {
216                         addDiff = false;
217                         flatIds.remove(arcDiff);
218
219                         if (otherDiffs != null) {
220                             otherDiffs.remove(oldOp);
221                         }
222                     }
223                 }
224             }
225             else if (property instanceof ToOneProperty) {
226
227                 if (currentArcSnapshot == null) {
228                     currentArcSnapshot = new HashMap JavaDoc();
229                 }
230
231                 currentArcSnapshot.put(arcId, targetId);
232             }
233             else {
234                 String JavaDoc message = (property == null)
235                         ? "No property for arcId " + arcId
236                         : "Unrecognized property for arcId " + arcId + ": " + property;
237                 throw new CayenneRuntimeException(message);
238             }
239         }
240
241         if (addDiff) {
242             if (otherDiffs == null) {
243                 otherDiffs = new ArrayList JavaDoc(3);
244             }
245
246             otherDiffs.add(diff);
247         }
248     }
249
250     /**
251      * Checks whether at least a single property is modified.
252      */

253     public boolean isNoop() {
254
255         // if we have no baseline to compare with, assume that there are changes
256
if (snapshot == null) {
257             return false;
258         }
259
260         if (flatIds != null && !flatIds.isEmpty()) {
261             return false;
262         }
263
264         final boolean[] modFound = new boolean[1];
265
266         int state = object.getPersistenceState();
267         if (state == PersistenceState.NEW || state == PersistenceState.DELETED) {
268             return false;
269         }
270
271         // check phantom mods
272

273         getClassDescriptor().visitProperties(new PropertyVisitor() {
274
275             public boolean visitAttribute(AttributeProperty property) {
276
277                 Object JavaDoc oldValue = snapshot.get(property.getName());
278                 Object JavaDoc newValue = property.readProperty(object);
279
280                 if (!Util.nullSafeEquals(oldValue, newValue)) {
281                     modFound[0] = true;
282                 }
283
284                 return !modFound[0];
285             }
286
287             public boolean visitToMany(ToManyProperty property) {
288                 // flattened changes
289
return true;
290             }
291
292             public boolean visitToOne(ToOneProperty property) {
293                 if (arcSnapshot == null) {
294                     return true;
295                 }
296
297                 Object JavaDoc newValue = property.readPropertyDirectly(object);
298                 if (newValue instanceof Fault) {
299                     return true;
300                 }
301
302                 Object JavaDoc oldValue = arcSnapshot.get(property.getName());
303                 if (!Util.nullSafeEquals(oldValue, newValue != null
304                         ? ((Persistent) newValue).getObjectId()
305                         : null)) {
306                     modFound[0] = true;
307                 }
308
309                 return !modFound[0];
310             }
311         });
312
313         return !modFound[0];
314     }
315
316     public void undo(GraphChangeHandler handler) {
317         throw new UnsupportedOperationException JavaDoc();
318     }
319
320     public void apply(final GraphChangeHandler handler) {
321
322         if (otherDiffs != null) {
323             Iterator JavaDoc it = otherDiffs.iterator();
324             while (it.hasNext()) {
325                 ((GraphDiff) it.next()).apply(handler);
326             }
327         }
328
329         applySimplePropertyChanges(handler);
330     }
331
332     private void applySimplePropertyChanges(final GraphChangeHandler handler) {
333
334         getClassDescriptor().visitProperties(new PropertyVisitor() {
335
336             public boolean visitAttribute(AttributeProperty property) {
337
338                 Object JavaDoc newValue = property.readProperty(object);
339
340                 // no baseline to compare
341
if (snapshot == null) {
342
343                     if (newValue != null) {
344                         handler.nodePropertyChanged(
345                                 nodeId,
346                                 property.getName(),
347                                 null,
348                                 newValue);
349                     }
350                 }
351                 // have baseline to compare
352
else {
353                     Object JavaDoc oldValue = snapshot.get(property.getName());
354
355                     if (!Util.nullSafeEquals(oldValue, newValue)) {
356                         handler.nodePropertyChanged(
357                                 nodeId,
358                                 property.getName(),
359                                 oldValue,
360                                 newValue);
361                     }
362                 }
363
364                 return true;
365             }
366
367             public boolean visitToMany(ToManyProperty property) {
368                 return true;
369             }
370
371             public boolean visitToOne(ToOneProperty property) {
372                 return true;
373             }
374         });
375     }
376
377     /**
378      * This is used to update faults.
379      */

380     void updateArcSnapshot(String JavaDoc propertyName, Persistent object) {
381         if (arcSnapshot == null) {
382             arcSnapshot = new HashMap JavaDoc();
383         }
384
385         arcSnapshot.put(propertyName, object != null ? object.getObjectId() : null);
386     }
387
388     static final class ArcOperation extends NodeDiff {
389
390         private Object JavaDoc targetNodeId;
391         private Object JavaDoc arcId;
392         private boolean delete;
393
394         public ArcOperation(Object JavaDoc nodeId, Object JavaDoc targetNodeId, Object JavaDoc arcId,
395                 boolean delete) {
396
397             super(nodeId);
398             this.targetNodeId = targetNodeId;
399             this.arcId = arcId;
400             this.delete = delete;
401         }
402
403         boolean isDelete() {
404             return delete;
405         }
406
407         public int hashCode() {
408             // assuming String and ObjectId provide a good hashCode
409
return arcId.hashCode() + targetNodeId.hashCode() + 5;
410         }
411
412         public boolean equals(Object JavaDoc object) {
413             // compare ignoring op type...
414
if (object == this) {
415                 return true;
416             }
417
418             if (object == null) {
419                 return false;
420             }
421
422             if (!(object instanceof ArcOperation)) {
423                 return false;
424             }
425
426             ArcOperation other = (ArcOperation) object;
427             return arcId.equals(other.arcId)
428                     && Util.nullSafeEquals(targetNodeId, other.targetNodeId);
429         }
430
431         public void apply(GraphChangeHandler tracker) {
432
433             if (delete) {
434                 tracker.arcDeleted(nodeId, targetNodeId, arcId);
435             }
436             else {
437                 tracker.arcCreated(nodeId, targetNodeId, arcId);
438             }
439         }
440
441         public void undo(GraphChangeHandler tracker) {
442             throw new UnsupportedOperationException JavaDoc();
443         }
444
445         public Object JavaDoc getArcId() {
446             return arcId;
447         }
448
449         public Object JavaDoc getTargetNodeId() {
450             return targetNodeId;
451         }
452     }
453 }
454
Popular Tags