1 19 20 package org.apache.cayenne.access; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.Map ; 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 51 class ObjectDiff extends NodeDiff { 52 53 private final String entityName; 54 55 private transient ClassDescriptor classDescriptor; 56 57 private Collection otherDiffs; 58 59 private Map snapshot; 60 private Map arcSnapshot; 61 private Map currentArcSnapshot; 62 private Map flatIds; 63 64 private Persistent object; 65 66 ObjectDiff(final Persistent object) { 67 68 super(object.getObjectId()); 69 70 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 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 (); 91 this.arcSnapshot = new HashMap (); 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 Object target = lock ? property.readProperty(object) : property 108 .readPropertyDirectly(object); 109 110 if (target instanceof Persistent) { 111 target = ((Persistent) target).getObjectId(); 112 } 113 115 arcSnapshot.put(property.getName(), target); 116 return true; 117 } 118 }); 119 } 120 } 121 122 Object getObject() { 123 return object; 124 } 125 126 ClassDescriptor getClassDescriptor() { 127 if (classDescriptor == null) { 129 EntityResolver entityResolver = object.getObjectContext().getEntityResolver(); 130 this.classDescriptor = entityResolver.getClassDescriptor(entityName); 131 } 132 133 return classDescriptor; 134 } 135 136 Object getSnapshotValue(String propertyName) { 137 return snapshot != null ? snapshot.get(propertyName) : null; 138 } 139 140 ObjectId getArcSnapshotValue(String propertyName) { 141 Object 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 propertyName) { 156 return arcSnapshot != null ? arcSnapshot.containsKey(propertyName) : false; 157 } 158 159 162 void appendDiffs(Collection 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 (); 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 targetId = arcDiff.getTargetNodeId(); 188 String arcId = arcDiff.getArcId().toString(); 189 190 Property property = getClassDescriptor().getProperty(arcId); 191 192 196 if (property instanceof ToManyProperty) { 197 198 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 (); 210 } 211 212 ArcOperation oldOp = (ArcOperation) flatIds.put(arcDiff, arcDiff); 213 214 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 (); 229 } 230 231 currentArcSnapshot.put(arcId, targetId); 232 } 233 else { 234 String 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 (3); 244 } 245 246 otherDiffs.add(diff); 247 } 248 } 249 250 253 public boolean isNoop() { 254 255 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 273 getClassDescriptor().visitProperties(new PropertyVisitor() { 274 275 public boolean visitAttribute(AttributeProperty property) { 276 277 Object oldValue = snapshot.get(property.getName()); 278 Object 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 return true; 290 } 291 292 public boolean visitToOne(ToOneProperty property) { 293 if (arcSnapshot == null) { 294 return true; 295 } 296 297 Object newValue = property.readPropertyDirectly(object); 298 if (newValue instanceof Fault) { 299 return true; 300 } 301 302 Object 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 (); 318 } 319 320 public void apply(final GraphChangeHandler handler) { 321 322 if (otherDiffs != null) { 323 Iterator 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 newValue = property.readProperty(object); 339 340 if (snapshot == null) { 342 343 if (newValue != null) { 344 handler.nodePropertyChanged( 345 nodeId, 346 property.getName(), 347 null, 348 newValue); 349 } 350 } 351 else { 353 Object 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 380 void updateArcSnapshot(String propertyName, Persistent object) { 381 if (arcSnapshot == null) { 382 arcSnapshot = new HashMap (); 383 } 384 385 arcSnapshot.put(propertyName, object != null ? object.getObjectId() : null); 386 } 387 388 static final class ArcOperation extends NodeDiff { 389 390 private Object targetNodeId; 391 private Object arcId; 392 private boolean delete; 393 394 public ArcOperation(Object nodeId, Object targetNodeId, Object 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 return arcId.hashCode() + targetNodeId.hashCode() + 5; 410 } 411 412 public boolean equals(Object object) { 413 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 (); 443 } 444 445 public Object getArcId() { 446 return arcId; 447 } 448 449 public Object getTargetNodeId() { 450 return targetNodeId; 451 } 452 } 453 } 454 | Popular Tags |