cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject svn commit: r632599 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src: main/java/org/apache/cayenne/access/ main/java/org/apache/cayenne/reflect/pojo/ main/java/org/apache/cayenne/reflect/valueholder/ test/java/org/apache/cayenne/remote/
Date Sat, 01 Mar 2008 15:21:33 GMT
Author: aadamchik
Date: Sat Mar  1 07:21:32 2008
New Revision: 632599

URL: http://svn.apache.org/viewvc?rev=632599&view=rev
Log:
CAY-789 return object diff to client in ROP after commit
(first working implementation. more testing is needed; need to filter out server entities)

Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/pojo/EnhancedPojoMapProperty.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/valueholder/ValueHolderMapProperty.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsTest.java

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
Sat Mar  1 07:21:32 2008
@@ -50,7 +50,33 @@
  */
 class ChildDiffLoader implements GraphChangeHandler {
 
-    ObjectContext context;
+    static final ThreadLocal<Boolean> childDiffProcessing = new ThreadLocal<Boolean>()
{
+
+        @Override
+        protected synchronized Boolean initialValue() {
+            return Boolean.FALSE;
+        }
+    };
+
+    private ObjectContext context;
+
+    /**
+     * Returns whether child diff processing is in progress.
+     * 
+     * @since 3.0
+     */
+    static boolean isProcessingChildDiff() {
+        return childDiffProcessing.get();
+    }
+
+    /**
+     * Sets whether child diff processing is in progress.
+     * 
+     * @since 3.0
+     */
+    static void setExternalChange(Boolean flag) {
+        childDiffProcessing.set(flag);
+    }
 
     ChildDiffLoader(ObjectContext context) {
         this.context = context;
@@ -61,30 +87,47 @@
     }
 
     public void nodeCreated(Object nodeId) {
-        ObjectId id = (ObjectId) nodeId;
-        if (id.getEntityName() == null) {
-            throw new NullPointerException("Null entity name in id " + id);
-        }
 
-        ObjEntity entity = context.getEntityResolver().getObjEntity(id.getEntityName());
-        if (entity == null) {
-            throw new IllegalArgumentException("Entity not mapped with Cayenne: " + id);
-        }
+        setExternalChange(Boolean.TRUE);
 
-        Persistent dataObject = null;
         try {
-            dataObject = (Persistent) entity.getJavaClass().newInstance();
+            ObjectId id = (ObjectId) nodeId;
+            if (id.getEntityName() == null) {
+                throw new NullPointerException("Null entity name in id " + id);
+            }
+
+            ObjEntity entity = context.getEntityResolver().getObjEntity(
+                    id.getEntityName());
+            if (entity == null) {
+                throw new IllegalArgumentException("Entity not mapped with Cayenne: "
+                        + id);
+            }
+
+            Persistent dataObject = null;
+            try {
+                dataObject = (Persistent) entity.getJavaClass().newInstance();
+            }
+            catch (Exception ex) {
+                throw new CayenneRuntimeException("Error instantiating object.", ex);
+            }
+
+            dataObject.setObjectId(id);
+            context.registerNewObject(dataObject);
         }
-        catch (Exception ex) {
-            throw new CayenneRuntimeException("Error instantiating object.", ex);
+        finally {
+            setExternalChange(Boolean.FALSE);
         }
-
-        dataObject.setObjectId(id);
-        context.registerNewObject(dataObject);
     }
 
     public void nodeRemoved(Object nodeId) {
-        context.deleteObject(findObject(nodeId));
+        setExternalChange(Boolean.TRUE);
+
+        try {
+            context.deleteObject(findObject(nodeId));
+        }
+        finally {
+            setExternalChange(Boolean.FALSE);
+        }
     }
 
     public void nodePropertyChanged(
@@ -99,12 +142,16 @@
         ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(
                 ((ObjectId) nodeId).getEntityName());
 
+        setExternalChange(Boolean.TRUE);
         try {
             descriptor.getProperty(property).writeProperty(object, null, newValue);
         }
         catch (Exception e) {
             throw new CayenneRuntimeException("Error setting property: " + property, e);
         }
+        finally {
+            setExternalChange(Boolean.FALSE);
+        }
     }
 
     public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
@@ -116,27 +163,33 @@
                 ((ObjectId) nodeId).getEntityName());
         ArcProperty property = (ArcProperty) descriptor.getProperty(arcId.toString());
 
-        property.visit(new PropertyVisitor() {
+        setExternalChange(Boolean.TRUE);
+        try {
+            property.visit(new PropertyVisitor() {
 
-            public boolean visitAttribute(AttributeProperty property) {
-                return false;
-            }
+                public boolean visitAttribute(AttributeProperty property) {
+                    return false;
+                }
 
-            public boolean visitToMany(ToManyProperty property) {
-                // connect reverse arc if the relationship is marked as "runtime"
-                ArcProperty reverseArc = property.getComplimentaryReverseArc();
-                boolean autoConnectReverse = reverseArc != null
-                        && reverseArc.getRelationship().isRuntime();
+                public boolean visitToMany(ToManyProperty property) {
+                    // connect reverse arc if the relationship is marked as "runtime"
+                    ArcProperty reverseArc = property.getComplimentaryReverseArc();
+                    boolean autoConnectReverse = reverseArc != null
+                            && reverseArc.getRelationship().isRuntime();
 
-                property.addTarget(source, target, autoConnectReverse);
-                return false;
-            }
+                    property.addTarget(source, target, autoConnectReverse);
+                    return false;
+                }
 
-            public boolean visitToOne(ToOneProperty property) {
-                property.setTarget(source, target, false);
-                return false;
-            }
-        });
+                public boolean visitToOne(ToOneProperty property) {
+                    property.setTarget(source, target, false);
+                    return false;
+                }
+            });
+        }
+        finally {
+            setExternalChange(Boolean.FALSE);
+        }
     }
 
     public void arcDeleted(Object nodeId, final Object targetNodeId, Object arcId) {
@@ -151,45 +204,54 @@
         ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(
                 ((ObjectId) nodeId).getEntityName());
         Property property = descriptor.getProperty(arcId.toString());
-        property.visit(new PropertyVisitor() {
 
-            public boolean visitAttribute(AttributeProperty property) {
-                return false;
-            }
-
-            public boolean visitToMany(ToManyProperty property) {
-                // connect reverse arc if the relationship is marked as "runtime"
-                ArcProperty reverseArc = property.getComplimentaryReverseArc();
-                boolean autoConnectReverse = reverseArc != null
-                        && reverseArc.getRelationship().isRuntime();
+        setExternalChange(Boolean.TRUE);
+        try {
+            property.visit(new PropertyVisitor() {
 
-                Persistent target = findObject(targetNodeId);
+                public boolean visitAttribute(AttributeProperty property) {
+                    return false;
+                }
 
-                if (target == null) {
+                public boolean visitToMany(ToManyProperty property) {
+                    // connect reverse arc if the relationship is marked as "runtime"
+                    ArcProperty reverseArc = property.getComplimentaryReverseArc();
+                    boolean autoConnectReverse = reverseArc != null
+                            && reverseArc.getRelationship().isRuntime();
+
+                    Persistent target = findObject(targetNodeId);
+
+                    if (target == null) {
+
+                        // this is usually the case when a NEW object was deleted and then
+                        // its
+                        // relationships were manipulated; so try to locate the object in
+                        // the
+                        // collection ...
+                        // the performance of this is rather dubious of course...
+                        target = findObjectInCollection(targetNodeId, property
+                                .readProperty(source));
+                    }
+
+                    if (target == null) {
+                        // ignore?
+                    }
+                    else {
+                        property.removeTarget(source, target, autoConnectReverse);
+                    }
 
-                    // this is usually the case when a NEW object was deleted and then its
-                    // relationships were manipulated; so try to locate the object in the
-                    // collection ...
-                    // the performance of this is rather dubious of course...
-                    target = findObjectInCollection(targetNodeId, property
-                            .readProperty(source));
+                    return false;
                 }
 
-                if (target == null) {
-                    // ignore?
-                }
-                else {
-                    property.removeTarget(source, target, autoConnectReverse);
+                public boolean visitToOne(ToOneProperty property) {
+                    property.setTarget(source, null, false);
+                    return false;
                 }
-
-                return false;
-            }
-
-            public boolean visitToOne(ToOneProperty property) {
-                property.setTarget(source, null, false);
-                return false;
-            }
-        });
+            });
+        }
+        finally {
+            setExternalChange(Boolean.FALSE);
+        }
     }
 
     Persistent findObject(Object nodeId) {
@@ -200,9 +262,9 @@
         if (object != null) {
             return object;
         }
-        
+
         ObjectId id = (ObjectId) nodeId;
-        
+
         // this can happen if a NEW object is deleted and after that its relationships are
         // modified
         if (id.isTemporary()) {
@@ -225,18 +287,19 @@
 
         return (Persistent) objects.get(0);
     }
-    
+
     Persistent findObjectInCollection(Object nodeId, Object toManyHolder) {
-        Collection c = (toManyHolder instanceof Map) ? ((Map) toManyHolder)
-                .values() : (Collection) toManyHolder;
+        Collection c = (toManyHolder instanceof Map)
+                ? ((Map) toManyHolder).values()
+                : (Collection) toManyHolder;
         Iterator it = c.iterator();
         while (it.hasNext()) {
             Persistent o = (Persistent) it.next();
-            if(nodeId.equals(o.getObjectId())) {
+            if (nodeId.equals(o.getObjectId())) {
                 return o;
             }
         }
-        
+
         return null;
     }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
Sat Mar  1 07:21:32 2008
@@ -1116,12 +1116,22 @@
             GraphDiff changes,
             boolean cascade) {
 
-        if (this != originatingContext && changes != null) {
-            changes.apply(new ChildDiffLoader(this));
-            fireDataChannelChanged(originatingContext, changes);
-        }
+        boolean childContext = this != originatingContext && changes != null;
+
+        try {
+            if (childContext) {
+                getObjectStore().childContextSyncStarted();
+                changes.apply(new ChildDiffLoader(this));
+                fireDataChannelChanged(originatingContext, changes);
+            }
 
-        return (cascade) ? flushToParent(true) : new CompoundDiff();
+            return (cascade) ? flushToParent(true) : new CompoundDiff();
+        }
+        finally {
+            if (childContext) {
+                getObjectStore().childContextSyncStopped();
+            }
+        }
     }
 
     /**
@@ -1141,6 +1151,7 @@
                 : DataChannel.FLUSH_NOCASCADE_SYNC;
 
         ObjectStore objectStore = getObjectStore();
+        GraphDiff parentChanges = null;
 
         // prevent multiple commits occuring simulteneously
         synchronized (objectStore) {
@@ -1153,46 +1164,62 @@
             if (noop) {
                 // need to clear phantom changes
                 objectStore.postprocessAfterPhantomCommit();
-                return new CompoundDiff();
             }
+            else {
 
-            try {
-                GraphDiff returnChanges = getChannel().onSync(this, changes, syncType);
+                try {
+                    parentChanges = getChannel().onSync(this, changes, syncType);
 
-                // note that this is a hack resulting from a fix to CAY-766... To support
-                // valid object state in PostPersist callback, 'postprocessAfterCommit' is
-                // invoked by DataDomain.onSync(..). Unless the parent is DataContext, and
-                // this method is not invoked!! As a result, PostPersist will contain temp
-                // ObjectIds in nested contexts and perm ones in flat contexts.
-                // Pending better callback design .....
-                if (objectStore.hasChanges()) {
-                    objectStore.postprocessAfterCommit(returnChanges);
+                    // note that this is a hack resulting from a fix to CAY-766... To
+                    // support
+                    // valid object state in PostPersist callback,
+                    // 'postprocessAfterCommit' is
+                    // invoked by DataDomain.onSync(..). Unless the parent is DataContext,
+                    // and
+                    // this method is not invoked!! As a result, PostPersist will contain
+                    // temp
+                    // ObjectIds in nested contexts and perm ones in flat contexts.
+                    // Pending better callback design .....
+                    if (objectStore.hasChanges()) {
+                        objectStore.postprocessAfterCommit(parentChanges);
+                    }
+
+                    // this event is caught by peer nested DataContexts to synchronize the
+                    // state
+                    fireDataChannelCommitted(this, changes);
                 }
-
-                // this event is caught by peer nested DataContexts to synchronize the
-                // state
-                fireDataChannelCommitted(this, changes);
-
-                // this event is caught by child DataContexts to update temporary
-                // ObjectIds with permanent
-                if (!returnChanges.isNoop()) {
-                    fireDataChannelCommitted(getChannel(), returnChanges);
+                // "catch" is needed to unwrap OptimisticLockExceptions
+                catch (CayenneRuntimeException ex) {
+                    Throwable unwound = Util.unwindException(ex);
+
+                    if (unwound instanceof CayenneRuntimeException) {
+                        throw (CayenneRuntimeException) unwound;
+                    }
+                    else {
+                        throw new CayenneRuntimeException("Commit Exception", unwound);
+                    }
                 }
+            }
+
+            // merge changes from parent as well as changes caused by lifecycle event
+            // callbacks/listeners...
 
-                return returnChanges;
+            CompoundDiff diff = new CompoundDiff();
+
+            diff.addAll(objectStore.getLifecycleEventInducedChanges());
+            if (parentChanges != null) {
+                diff.add(parentChanges);
             }
-            // "catch" is needed to unwrap OptimisticLockExceptions
-            catch (CayenneRuntimeException ex) {
-                Throwable unwound = Util.unwindException(ex);
 
-                if (unwound instanceof CayenneRuntimeException) {
-                    throw (CayenneRuntimeException) unwound;
-                }
-                else {
-                    throw new CayenneRuntimeException("Commit Exception", unwound);
-                }
+            // this event is caught by child DataContexts to update temporary
+            // ObjectIds with permanent
+            if (!diff.isNoop()) {
+                fireDataChannelCommitted(getChannel(), diff);
             }
+
+            return diff;
         }
+
     }
 
     /**

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectStore.java
Sat Mar  1 07:21:32 2008
@@ -43,6 +43,7 @@
 import org.apache.cayenne.graph.NodeCreateOperation;
 import org.apache.cayenne.graph.NodeDeleteOperation;
 import org.apache.cayenne.graph.NodeDiff;
+import org.apache.cayenne.graph.NodePropertyChangeOperation;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.ObjEntity;
@@ -105,6 +106,8 @@
     // used to avoid incorrect on-demand DataRowStore initialization after deserialization
     private boolean dataRowCacheSet;
 
+    private Collection<GraphDiff> lifecycleEventInducedChanges;
+
     /**
      * The DataContext that owns this ObjectStore.
      */
@@ -132,6 +135,39 @@
     }
 
     /**
+     * @since 3.0
+     */
+    void childContextSyncStarted() {
+        lifecycleEventInducedChanges = new ArrayList<GraphDiff>();
+    }
+
+    /**
+     * @since 3.0
+     */
+    void childContextSyncStopped() {
+        lifecycleEventInducedChanges = null;
+    }
+
+    /**
+     * @since 3.0
+     */
+    Collection<GraphDiff> getLifecycleEventInducedChanges() {
+        return lifecycleEventInducedChanges != null
+                ? lifecycleEventInducedChanges
+                : Collections.EMPTY_LIST;
+    }
+
+    void registerLifecycleEventInducedChange(GraphDiff diff) {
+        if (ChildDiffLoader.isProcessingChildDiff()) {
+            // reset so that subsequent event-induced changes could get registered...
+            ChildDiffLoader.setExternalChange(Boolean.FALSE);
+        }
+        else {
+            lifecycleEventInducedChanges.add(diff);
+        }
+    }
+
+    /**
      * Registers object change.
      * 
      * @since 1.2
@@ -570,7 +606,7 @@
 
         if (context != null && context.getChannel() != null) {
             ObjectIdQuery query = new ObjectIdQuery(oid, true, ObjectIdQuery.CACHE);
-            List results = context.getChannel().onQuery(context, query).firstList();
+            List<?> results = context.getChannel().onQuery(context, query).firstList();
             return results.isEmpty() ? null : (DataRow) results.get(0);
         }
         else {
@@ -998,14 +1034,27 @@
      * @since 1.2
      */
     public void nodeCreated(Object nodeId) {
-        registerDiff(nodeId, new NodeCreateOperation(nodeId));
+        NodeDiff diff = new NodeCreateOperation(nodeId);
+
+        if (lifecycleEventInducedChanges != null) {
+            registerLifecycleEventInducedChange(diff);
+        }
+
+        registerDiff(nodeId, diff);
     }
 
     /**
      * @since 1.2
      */
     public void nodeRemoved(Object nodeId) {
-        registerDiff(nodeId, new NodeDeleteOperation(nodeId));
+
+        NodeDiff diff = new NodeDeleteOperation(nodeId);
+
+        if (lifecycleEventInducedChanges != null) {
+            registerLifecycleEventInducedChange(diff);
+        }
+
+        registerDiff(nodeId, diff);
     }
 
     /**
@@ -1019,6 +1068,14 @@
             Object oldValue,
             Object newValue) {
 
+        if (lifecycleEventInducedChanges != null) {
+            registerLifecycleEventInducedChange(new NodePropertyChangeOperation(
+                    nodeId,
+                    property,
+                    oldValue,
+                    newValue));
+        }
+
         registerDiff(nodeId, null);
     }
 
@@ -1026,22 +1083,26 @@
      * @since 1.2
      */
     public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
-        registerDiff(nodeId, new ArcOperation(
-                nodeId,
-                targetNodeId,
-                arcId.toString(),
-                false));
+        NodeDiff diff = new ArcOperation(nodeId, targetNodeId, arcId.toString(), false);
+
+        if (lifecycleEventInducedChanges != null) {
+            registerLifecycleEventInducedChange(diff);
+        }
+
+        registerDiff(nodeId, diff);
     }
 
     /**
      * @since 1.2
      */
     public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
-        registerDiff(nodeId, new ArcOperation(
-                nodeId,
-                targetNodeId,
-                arcId.toString(),
-                true));
+        NodeDiff diff = new ArcOperation(nodeId, targetNodeId, arcId.toString(), true);
+
+        if (lifecycleEventInducedChanges != null) {
+            registerLifecycleEventInducedChange(diff);
+        }
+
+        registerDiff(nodeId, diff);
     }
 
     // an ObjectIdQuery optimized for retrieval of multiple snapshots - it can be reset

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/pojo/EnhancedPojoMapProperty.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/pojo/EnhancedPojoMapProperty.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/pojo/EnhancedPojoMapProperty.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/pojo/EnhancedPojoMapProperty.java
Sat Mar  1 07:21:32 2008
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.reflect.pojo;
 
+import java.util.Map;
+
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.ValueHolder;
 import org.apache.cayenne.reflect.Accessor;
@@ -44,6 +46,36 @@
     @Override
     protected ValueHolder createValueHolder(Persistent relationshipOwner) {
         return new PersistentObjectMap(relationshipOwner, getName(), mapKeyAccessor);
+    }
+    
+    @Override
+    public void addTarget(Object source, Object target, boolean setReverse) {
+
+        if (target == null) {
+            throw new NullPointerException("Attempt to add null object.");
+        }
+
+        // Now do the rest of the normal handling (regardless of whether it was
+        // flattened or not)
+        Map<Object, Object> collection = (Map<Object, Object>) readProperty(source);
+        collection.put(getMapKey(target), target);
+
+        if (setReverse) {
+            setReverse(source, null, target);
+        }
+    }
+
+    @Override
+    public void removeTarget(Object source, Object target, boolean setReverse) {
+
+        // Now do the rest of the normal handling (regardless of whether it was
+        // flattened or not)
+        Map<Object, Object> collection = (Map<Object, Object>) readProperty(source);
+        collection.remove(getMapKey(target));
+
+        if (target != null && setReverse) {
+            setReverse(source, target, null);
+        }
     }
 
     public Object getMapKey(Object target) throws PropertyException {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/valueholder/ValueHolderMapProperty.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/valueholder/ValueHolderMapProperty.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/valueholder/ValueHolderMapProperty.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/valueholder/ValueHolderMapProperty.java
Sat Mar  1 07:21:32 2008
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.reflect.valueholder;
 
+import java.util.Map;
+
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.ValueHolder;
 import org.apache.cayenne.reflect.Accessor;
@@ -39,6 +41,36 @@
             Accessor accessor, String reverseName, Accessor mapKeyAccessor) {
         super(owner, targetDescriptor, accessor, reverseName);
         this.mapKeyAccessor = mapKeyAccessor;
+    }
+
+    @Override
+    public void addTarget(Object source, Object target, boolean setReverse) {
+
+        if (target == null) {
+            throw new NullPointerException("Attempt to add null object.");
+        }
+
+        // Now do the rest of the normal handling (regardless of whether it was
+        // flattened or not)
+        Map<Object, Object> collection = (Map<Object, Object>) readProperty(source);
+        collection.put(getMapKey(target), target);
+
+        if (setReverse) {
+            setReverse(source, null, target);
+        }
+    }
+
+    @Override
+    public void removeTarget(Object source, Object target, boolean setReverse) {
+
+        // Now do the rest of the normal handling (regardless of whether it was
+        // flattened or not)
+        Map<Object, Object> collection = (Map<Object, Object>) readProperty(source);
+        collection.remove(getMapKey(target));
+
+        if (target != null && setReverse) {
+            setReverse(source, target, null);
+        }
     }
 
     @Override

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsTest.java?rev=632599&r1=632598&r2=632599&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsTest.java
(original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsTest.java
Sat Mar  1 07:21:32 2008
@@ -31,6 +31,7 @@
 import org.apache.cayenne.reflect.LifecycleCallbackRegistry;
 import org.apache.cayenne.remote.service.LocalConnection;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
 import org.apache.cayenne.testdo.mt.MtTable1;
 import org.apache.cayenne.unit.AccessStack;
 import org.apache.cayenne.unit.CayenneCase;
@@ -88,7 +89,7 @@
     public void testReturnDiffInPrePersist() {
 
         final List<GenericDiff> diffs = new ArrayList<GenericDiff>();
-        final GraphChangeHandler diffReader = new NoopGraphChangeHandler() {
+        final NoopGraphChangeHandler diffReader = new NoopGraphChangeHandler() {
 
             @Override
             public void nodePropertyChanged(
@@ -96,6 +97,8 @@
                     String property,
                     Object oldValue,
                     Object newValue) {
+
+                super.nodePropertyChanged(nodeId, property, oldValue, newValue);
                 diffs
                         .add(new GenericDiff(
                                 (ObjectId) nodeId,
@@ -103,6 +106,7 @@
                                 oldValue,
                                 newValue));
             }
+
         };
 
         LifecycleCallbackRegistry registry = getDomain()
@@ -139,42 +143,95 @@
 
             CayenneContext context = new CayenneContext(channel);
             ClientMtTable1 o = context.newObject(ClientMtTable1.class);
+            ObjectId tempId = o.getObjectId();
             o.setServerAttribute1("YY");
             context.commitChanges();
 
-//            assertEquals(1, diffs.size());
-//            assertEquals(o.getObjectId(), diffs.get(0).sourceId);
-//            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, diffs.get(0).property);
-//            assertNull(diffs.get(0).oldValue);
-//            assertEquals("XXX", diffs.get(0).newValue);
+            assertEquals(2, diffReader.size);
+            assertEquals(1, diffs.size());
+            assertEquals(tempId, diffs.get(0).sourceId);
+            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, diffs.get(0).property);
+            assertNull(diffs.get(0).oldValue);
+            assertEquals("XXX", diffs.get(0).newValue);
         }
         finally {
             registry.clear();
         }
     }
 
+    public void testReturnDiffClientArcChanges() {
+
+        final NoopGraphChangeHandler diffReader = new NoopGraphChangeHandler();
+
+        ClientServerChannel csChannel = new ClientServerChannel(getDomain());
+        ClientChannel channel = new ClientChannel(new LocalConnection(csChannel)) {
+
+            @Override
+            public GraphDiff onSync(
+                    ObjectContext originatingContext,
+                    GraphDiff changes,
+                    int syncType) {
+
+                GraphDiff serverDiff = super
+                        .onSync(originatingContext, changes, syncType);
+
+                assertNotNull(serverDiff);
+                serverDiff.apply(diffReader);
+                return serverDiff;
+            }
+        };
+
+        CayenneContext context = new CayenneContext(channel);
+        ClientMtTable1 o = context.newObject(ClientMtTable1.class);
+        ClientMtTable2 o2 = context.newObject(ClientMtTable2.class);
+        o.addToTable2Array(o2);
+        context.commitChanges();
+
+        assertEquals(2, diffReader.size);
+
+        diffReader.reset();
+
+        ClientMtTable2 o3 = context.newObject(ClientMtTable2.class);
+        o3.setTable1(o);
+        context.commitChanges();
+        assertEquals(1, diffReader.size);
+    }
+
     class NoopGraphChangeHandler implements GraphChangeHandler {
 
+        int size;
+
+        void reset() {
+            size = 0;
+        }
+
+        public void nodePropertyChanged(
+                Object nodeId,
+                String property,
+                Object oldValue,
+                Object newValue) {
+
+            size++;
+        }
+
         public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+            size++;
         }
 
         public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+            size++;
         }
 
         public void nodeCreated(Object nodeId) {
+            size++;
         }
 
         public void nodeIdChanged(Object nodeId, Object newId) {
-        }
-
-        public void nodePropertyChanged(
-                Object nodeId,
-                String property,
-                Object oldValue,
-                Object newValue) {
+            size++;
         }
 
         public void nodeRemoved(Object nodeId) {
+            size++;
         }
     }
 



Mime
View raw message