You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/11/26 02:37:42 UTC

svn commit: r479252 - in /incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src: main/java/org/apache/cayenne/access/ main/java/org/apache/cayenne/reflect/ main/java/org/apache/cayenne/reflect/generic/ main/java/org/apache/cayenne/util/ test/java/org/ap...

Author: aadamchik
Date: Sat Nov 25 17:37:41 2006
New Revision: 479252

URL: http://svn.apache.org/viewvc?view=rev&rev=479252
Log:
CAY-686: Weed out DataObject references from the access stack classes, replacing them with Persistent and ClassDescriptor
(implementing DataObject property descriptors that work as callbacks of the dataobject methods, i.e. the correct descriptors)

Added:
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectAttributeProperty.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectBaseProperty.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToOneProperty.java
Removed:
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/PersistentObjectProperty.java
Modified:
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/SimpleAttributeProperty.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectDescriptorFactory.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToManyProperty.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/DataObjectSerializationTest.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/access/DataContextSharedCacheTest.java

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java Sat Nov 25 17:37:41 2006
@@ -25,12 +25,18 @@
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
 import org.apache.cayenne.QueryResponse;
 import org.apache.cayenne.graph.GraphChangeHandler;
 import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.Relationship;
 import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.query.Query;
+import org.apache.cayenne.reflect.AttributeProperty;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.Property;
+import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyProperty;
+import org.apache.cayenne.reflect.ToOneProperty;
 
 /**
  * A GraphChangeHandler that loads child ObjectContext diffs into a parent DataContext.
@@ -43,7 +49,7 @@
 
     ObjectContext context;
 
-    ChildDiffLoader(DataContext context) {
+    ChildDiffLoader(ObjectContext context) {
         this.context = context;
     }
 
@@ -88,10 +94,12 @@
 
         // this change is for simple property, so no need to convert targets to server
         // objects...
-        DataObject object = findObject(nodeId);
+        Persistent object = findObject(nodeId);
+        ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(
+                ((ObjectId) nodeId).getEntityName());
 
         try {
-            object.writeProperty(property, newValue);
+            descriptor.getProperty(property).writeProperty(object, null, newValue);
         }
         catch (Exception e) {
             throw new CayenneRuntimeException("Error setting property: " + property, e);
@@ -100,42 +108,61 @@
 
     public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
 
-        DataObject source = findObject(nodeId);
+        final Persistent source = findObject(nodeId);
+        final Persistent target = findObject(targetNodeId);
 
-        // find whether this is to-one or to-many
-        ObjEntity sourceEntity = context.getEntityResolver().lookupObjEntity(source);
-        Relationship relationship = sourceEntity.getRelationship(arcId.toString());
+        ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(
+                ((ObjectId) nodeId).getEntityName());
+        Property property = descriptor.getProperty(arcId.toString());
 
-        DataObject target = findObject(targetNodeId);
-        if (relationship.isToMany()) {
-            source.addToManyTarget(relationship.getName(), target, false);
-        }
-        else {
-            source.setToOneTarget(relationship.getName(), target, false);
-        }
+        property.visit(new PropertyVisitor() {
+
+            public boolean visitAttribute(AttributeProperty property) {
+                return false;
+            }
+
+            public boolean visitToMany(ToManyProperty property) {
+                property.addTarget(source, target, false);
+                return false;
+            }
+
+            public boolean visitToOne(ToOneProperty property) {
+                property.setTarget(source, target, false);
+                return false;
+            }
+        });
     }
 
-    public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
-        DataObject source = findObject(nodeId);
+    public void arcDeleted(Object nodeId, final Object targetNodeId, Object arcId) {
+        final Persistent source = findObject(nodeId);
 
-        // find whether this is to-one or to-many
-        ObjEntity sourceEntity = context.getEntityResolver().lookupObjEntity(source);
-        Relationship relationship = sourceEntity.getRelationship(arcId.toString());
+        ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(
+                ((ObjectId) nodeId).getEntityName());
+        Property property = descriptor.getProperty(arcId.toString());
+        property.visit(new PropertyVisitor() {
 
-        DataObject target = findObject(targetNodeId);
-        if (relationship.isToMany()) {
-            source.removeToManyTarget(relationship.getName(), target, false);
-        }
-        else {
-            source.setToOneTarget(relationship.getName(), null, false);
-        }
+            public boolean visitAttribute(AttributeProperty property) {
+                return false;
+            }
+
+            public boolean visitToMany(ToManyProperty property) {
+                Persistent target = findObject(targetNodeId);
+                property.removeTarget(source, target, false);
+                return false;
+            }
+
+            public boolean visitToOne(ToOneProperty property) {
+                property.setTarget(source, null, false);
+                return false;
+            }
+        });
     }
 
-    DataObject findObject(Object nodeId) {
+    Persistent findObject(Object nodeId) {
         // first do a lookup in ObjectStore; if even a hollow object is found, return it;
         // if not - fetch.
 
-        DataObject object = (DataObject) context.getGraphManager().getNode(nodeId);
+        Persistent object = (Persistent) context.getGraphManager().getNode(nodeId);
         if (object != null) {
             return object;
         }
@@ -154,6 +181,6 @@
                             + objects.size());
         }
 
-        return (DataObject) objects.get(0);
+        return (Persistent) objects.get(0);
     }
 }

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java Sat Nov 25 17:37:41 2006
@@ -28,8 +28,10 @@
 import org.apache.cayenne.graph.GraphChangeHandler;
 import org.apache.cayenne.graph.GraphDiff;
 import org.apache.cayenne.graph.GraphEvent;
+import org.apache.cayenne.reflect.AttributeProperty;
 import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.reflect.Property;
+import org.apache.cayenne.reflect.PropertyVisitor;
 import org.apache.cayenne.reflect.ToManyProperty;
 import org.apache.cayenne.reflect.ToOneProperty;
 import org.apache.cayenne.util.Util;
@@ -41,6 +43,9 @@
  * @since 1.2
  * @author Andrus Adamchik
  */
+// TODO: andrus, 11/25/2006 - this logic is the same as the logic in DataRowUtils used to
+// merge snapshot changes. Any way to reconclie the two? (in fact DataRowUtils is more
+// comprehensive)
 class DataContextMergeHandler implements GraphChangeHandler, DataChannelListener {
 
     private boolean active;
@@ -159,37 +164,45 @@
     }
 
     public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+        arcChanged(nodeId, targetNodeId, arcId);
+    }
+
+    public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+        arcChanged(nodeId, targetNodeId, arcId);
+    }
+
+    // works the same for add and remove as long as we don't get too smart per TODO below.
+    private void arcChanged(Object nodeId, Object targetNodeId, Object arcId) {
 
-        Persistent source = (Persistent) context.getGraphManager().getNode(nodeId);
+        final Persistent source = (Persistent) context.getGraphManager().getNode(nodeId);
         if (source != null && source.getPersistenceState() != PersistenceState.HOLLOW) {
 
-            // get target as local object
-            Object target = context.localObject((ObjectId) targetNodeId, null);
+            final int state = source.getPersistenceState();
 
             Property p = propertyForId(nodeId, arcId.toString());
-            if (p instanceof ToManyProperty) {
-                ((ToManyProperty) p).addTarget(source, target, false);
-            }
-            else {
-                ((ToOneProperty) p).setTarget(source, target, false);
-            }
-        }
-    }
+            p.visit(new PropertyVisitor() {
 
-    public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+                public boolean visitAttribute(AttributeProperty property) {
+                    return false;
+                }
 
-        Persistent source = (Persistent) context.getGraphManager().getNode(nodeId);
-        if (source != null && source.getPersistenceState() != PersistenceState.HOLLOW) {
+                public boolean visitToMany(ToManyProperty property) {
+                    if (state == PersistenceState.COMMITTED) {
+                        property.invalidate(source);
+                    }
 
-            Object target = context.localObject((ObjectId) targetNodeId, null);
+                    return false;
+                }
 
-            Property p = propertyForId(nodeId, arcId.toString());
-            if (p instanceof ToManyProperty) {
-                ((ToManyProperty) p).removeTarget(source, target, false);
-            }
-            else {
-                ((ToOneProperty) p).setTarget(source, null, false);
-            }
+                public boolean visitToOne(ToOneProperty property) {
+                    if (state == PersistenceState.COMMITTED) {
+                        property.invalidate(source);
+                    }
+                    // TODO: andrus, 11/25/2006 - handle replacement of clean properties
+                    // of dirty objects. See DataRowUtils for details.
+                    return false;
+                }
+            });
         }
     }
 }

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java Sat Nov 25 17:37:41 2006
@@ -30,6 +30,7 @@
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.DataRow;
+import org.apache.cayenne.Persistent;
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.parser.ASTPath;
@@ -81,7 +82,7 @@
         return resolvedRows;
     }
 
-    void addObject(DataObject object, DataRow row) {
+    void addObject(Persistent object, DataRow row) {
         objects.add(object);
         resolvedRows.add(row);
     }

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/SimpleAttributeProperty.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/SimpleAttributeProperty.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/SimpleAttributeProperty.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/SimpleAttributeProperty.java Sat Nov 25 17:37:41 2006
@@ -57,7 +57,7 @@
         super.writeProperty(object, oldValue, newValue);
     }
 
-    void resolveFault(Object object) throws PropertyException {
+    protected void resolveFault(Object object) throws PropertyException {
         try {
             Persistent persistent = (Persistent) object;
             ObjectContext context = persistent.getObjectContext();

Added: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectAttributeProperty.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectAttributeProperty.java?view=auto&rev=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectAttributeProperty.java (added)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectAttributeProperty.java Sat Nov 25 17:37:41 2006
@@ -0,0 +1,49 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.reflect.generic;
+
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.reflect.AttributeProperty;
+import org.apache.cayenne.reflect.PropertyException;
+import org.apache.cayenne.reflect.PropertyVisitor;
+
+class DataObjectAttributeProperty extends DataObjectBaseProperty implements
+        AttributeProperty {
+
+    protected ObjAttribute attribute;
+
+    public DataObjectAttributeProperty(ObjAttribute attribute) {
+        this.attribute = attribute;
+    }
+
+    public String getName() {
+        return attribute.getName();
+    }
+
+    public ObjAttribute getAttribute() {
+        return attribute;
+    }
+
+    public void injectValueHolder(Object object) throws PropertyException {
+    }
+
+    public boolean visit(PropertyVisitor visitor) {
+        return visitor.visitAttribute(this);
+    }
+}

Added: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectBaseProperty.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectBaseProperty.java?view=auto&rev=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectBaseProperty.java (added)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectBaseProperty.java Sat Nov 25 17:37:41 2006
@@ -0,0 +1,104 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.reflect.generic;
+
+import org.apache.cayenne.DataObject;
+import org.apache.cayenne.reflect.Property;
+import org.apache.cayenne.reflect.PropertyException;
+import org.apache.cayenne.reflect.PropertyVisitor;
+
+/**
+ * A superclass of DataObject properties that accesses object via DataObject methods.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+abstract class DataObjectBaseProperty implements Property {
+
+    public abstract String getName();
+
+    public abstract void injectValueHolder(Object object) throws PropertyException;
+
+    public abstract boolean visit(PropertyVisitor visitor);
+
+    public Object readProperty(Object object) throws PropertyException {
+        try {
+            return toDataObject(object).readProperty(getName());
+        }
+        catch (Throwable th) {
+            throw new PropertyException(
+                    "Error reading DataObject property: " + getName(),
+                    this,
+                    object,
+                    th);
+        }
+    }
+
+    public void writeProperty(Object object, Object oldValue, Object newValue)
+            throws PropertyException {
+        try {
+            toDataObject(object).writeProperty(getName(), newValue);
+        }
+        catch (Throwable th) {
+            throw new PropertyException(
+                    "Error writing DataObject property: " + getName(),
+                    this,
+                    object,
+                    th);
+        }
+    }
+
+    public Object readPropertyDirectly(Object object) throws PropertyException {
+        try {
+            return toDataObject(object).readPropertyDirectly(getName());
+        }
+        catch (Throwable th) {
+            throw new PropertyException(
+                    "Error reading DataObject property: " + getName(),
+                    this,
+                    object,
+                    th);
+        }
+    }
+
+    public void writePropertyDirectly(Object object, Object oldValue, Object newValue)
+            throws PropertyException {
+        try {
+            toDataObject(object).writePropertyDirectly(getName(), newValue);
+        }
+        catch (Throwable th) {
+            throw new PropertyException(
+                    "Error writing DataObject property: " + getName(),
+                    this,
+                    object,
+                    th);
+        }
+    }
+
+    protected final DataObject toDataObject(Object object) throws PropertyException {
+        try {
+            return (DataObject) object;
+        }
+        catch (ClassCastException e) {
+            throw new PropertyException("Object is not a DataObject: '"
+                    + object.getClass().getName()
+                    + "'", this, object, e);
+        }
+    }
+}

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectDescriptorFactory.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectDescriptorFactory.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectDescriptorFactory.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectDescriptorFactory.java Sat Nov 25 17:37:41 2006
@@ -18,9 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.reflect.generic;
 
-import java.util.List;
-
 import org.apache.cayenne.DataObject;
+import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
 import org.apache.cayenne.reflect.Accessor;
@@ -29,7 +28,6 @@
 import org.apache.cayenne.reflect.ClassDescriptorMap;
 import org.apache.cayenne.reflect.PersistentDescriptor;
 import org.apache.cayenne.reflect.PersistentDescriptorFactory;
-import org.apache.cayenne.reflect.PersistentObjectProperty;
 import org.apache.cayenne.reflect.PropertyException;
 
 /**
@@ -57,20 +55,21 @@
         return new DataObjectDescriptor();
     }
 
+    protected void createAttributeProperty(
+            PersistentDescriptor descriptor,
+            ObjAttribute attribute) {
+        descriptor.addDeclaredProperty(new DataObjectAttributeProperty(attribute));
+    }
+
     protected void createToManyProperty(
             PersistentDescriptor descriptor,
             ObjRelationship relationship) {
 
         ClassDescriptor targetDescriptor = descriptorMap.getDescriptor(relationship
                 .getTargetEntityName());
-        String reverseName = relationship.getReverseRelationshipName();
-        Accessor accessor = createAccessor(descriptor, relationship.getName(), List.class);
-
         descriptor.addDeclaredProperty(new DataObjectToManyProperty(
-                descriptor,
-                targetDescriptor,
-                accessor,
-                reverseName));
+                relationship,
+                targetDescriptor));
     }
 
     protected void createToOneProperty(
@@ -79,18 +78,9 @@
 
         ClassDescriptor targetDescriptor = descriptorMap.getDescriptor(relationship
                 .getTargetEntityName());
-        String reverseName = relationship.getReverseRelationshipName();
-        ObjEntity targetEntity = (ObjEntity) relationship.getTargetEntity();
-        Accessor accessor = createAccessor(
-                descriptor,
-                relationship.getName(),
-                targetEntity.getJavaClass());
-        descriptor.addDeclaredProperty(new PersistentObjectProperty(
-                descriptor,
-                targetDescriptor,
-                accessor,
-                reverseName));
-
+        descriptor.addDeclaredProperty(new DataObjectToOneProperty(
+                relationship,
+                targetDescriptor));
     }
 
     protected Accessor createAccessor(

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToManyProperty.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToManyProperty.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToManyProperty.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToManyProperty.java Sat Nov 25 17:37:41 2006
@@ -22,10 +22,12 @@
 import org.apache.cayenne.Fault;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.reflect.Accessor;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.ArcProperty;
 import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.ListProperty;
 import org.apache.cayenne.reflect.PropertyException;
+import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToManyProperty;
 
 /**
  * A list property that is intended to work with
@@ -34,29 +36,90 @@
  * @since 3.0
  * @author Andrus Adamchik
  */
-class DataObjectToManyProperty extends ListProperty {
+class DataObjectToManyProperty extends DataObjectBaseProperty implements ToManyProperty {
 
-    DataObjectToManyProperty(ClassDescriptor owner, ClassDescriptor targetDescriptor,
-            Accessor accessor, String reverseName) {
-        super(owner, targetDescriptor, accessor, reverseName);
+    protected ObjRelationship relationship;
+    protected String reverseName;
+    protected ClassDescriptor targetDescriptor;
+
+    DataObjectToManyProperty(ObjRelationship relationship,
+            ClassDescriptor targetDescriptor) {
+        this.relationship = relationship;
+        this.targetDescriptor = targetDescriptor;
+        this.reverseName = relationship.getReverseRelationshipName();
     }
 
-    protected ValueHolder createCollectionValueHolder(Object object)
+    public ArcProperty getComplimentaryReverseArc() {
+        return reverseName != null ? (ArcProperty) targetDescriptor
+                .getProperty(reverseName) : null;
+    }
+
+    public ClassDescriptor getTargetDescriptor() {
+        return targetDescriptor;
+    }
+
+    public String getName() {
+        return relationship.getName();
+    }
+
+    public ObjRelationship getRelationship() {
+        return relationship;
+    }
+
+    public void addTarget(Object source, Object target, boolean setReverse)
+            throws PropertyException {
+        try {
+            toDataObject(source).addToManyTarget(
+                    getName(),
+                    toDataObject(target),
+                    setReverse);
+        }
+        catch (Throwable th) {
+            throw new PropertyException("Error setting to-many DataObject property: "
+                    + getName(), this, source, th);
+        }
+    }
+
+    public void removeTarget(Object source, Object target, boolean setReverse)
             throws PropertyException {
-        if (!(object instanceof Persistent)) {
+        try {
+            toDataObject(source).removeToManyTarget(
+                    getName(),
+                    toDataObject(target),
+                    setReverse);
+        }
+        catch (Throwable th) {
+            throw new PropertyException("Error unsetting to-many DataObject property: "
+                    + getName(), this, source, th);
+        }
+    }
 
-            throw new PropertyException(
-                    "ValueHolders for non-persistent objects are not supported.",
-                    this,
-                    object);
+    public void injectValueHolder(Object object) throws PropertyException {
+        if (readPropertyDirectly(object) == null) {
+            writePropertyDirectly(object, null, Fault.getToManyFault().resolveFault(
+                    (Persistent) object,
+                    getName()));
         }
+    }
 
-        return (ValueHolder) Fault.getToManyFault().resolveFault(
-                (Persistent) object,
-                getName());
+    public boolean isFault(Object source) {
+        return readPropertyDirectly(source) instanceof Fault;
+    }
+
+    public boolean visit(PropertyVisitor visitor) {
+        return visitor.visitToMany(this);
     }
 
     public void invalidate(Object object) {
-        writePropertyDirectly(object, null, Fault.getToManyFault());
+        Object value = readPropertyDirectly(object);
+        if (value instanceof Fault) {
+            // nothing to do
+        }
+        else if (value instanceof ValueHolder) {
+            ((ValueHolder) value).invalidate();
+        }
+        else {
+            writePropertyDirectly(object, null, Fault.getToManyFault());
+        }
     }
 }

Added: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToOneProperty.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToOneProperty.java?view=auto&rev=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToOneProperty.java (added)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/reflect/generic/DataObjectToOneProperty.java Sat Nov 25 17:37:41 2006
@@ -0,0 +1,92 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.reflect.generic;
+
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.ArcProperty;
+import org.apache.cayenne.reflect.ClassDescriptor;
+import org.apache.cayenne.reflect.PropertyException;
+import org.apache.cayenne.reflect.PropertyVisitor;
+import org.apache.cayenne.reflect.ToOneProperty;
+
+/**
+ * An ArcProperty for accessing to-one relationships.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+class DataObjectToOneProperty extends DataObjectBaseProperty implements ToOneProperty {
+
+    protected ObjRelationship relationship;
+    protected String reverseName;
+    protected ClassDescriptor targetDescriptor;
+
+    DataObjectToOneProperty(ObjRelationship relationship, ClassDescriptor targetDescriptor) {
+        this.relationship = relationship;
+        this.targetDescriptor = targetDescriptor;
+        this.reverseName = relationship.getReverseRelationshipName();
+    }
+
+    public ArcProperty getComplimentaryReverseArc() {
+        return reverseName != null ? (ArcProperty) targetDescriptor
+                .getProperty(reverseName) : null;
+    }
+
+    public ClassDescriptor getTargetDescriptor() {
+        return targetDescriptor;
+    }
+
+    public String getName() {
+        return relationship.getName();
+    }
+
+    public ObjRelationship getRelationship() {
+        return relationship;
+    }
+
+    public void injectValueHolder(Object object) throws PropertyException {
+    }
+
+    public void setTarget(Object source, Object target, boolean setReverse) {
+        try {
+            toDataObject(source).setToOneTarget(
+                    getName(),
+                    toDataObject(target),
+                    setReverse);
+        }
+        catch (Throwable th) {
+            throw new PropertyException("Error setting to-one DataObject property: "
+                    + getName(), this, source, th);
+        }
+    }
+
+    public boolean visit(PropertyVisitor visitor) {
+        return visitor.visitToOne(this);
+    }
+
+    public boolean isFault(Object object) {
+        return readPropertyDirectly(object) instanceof Fault;
+    }
+
+    public void invalidate(Object object) {
+        writePropertyDirectly(object, null, Fault.getToOneFault());
+    }
+}

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/main/java/org/apache/cayenne/util/DeepMergeOperation.java Sat Nov 25 17:37:41 2006
@@ -92,7 +92,7 @@
 
                     Object oldTarget = property.isFault(target) ? null : property
                             .readProperty(target);
-                    property.writeProperty(target, oldTarget, destinationTarget);
+                    property.writePropertyDirectly(target, oldTarget, destinationTarget);
                 }
 
                 return true;
@@ -114,7 +114,7 @@
                         targetCollection.add(destinationTarget);
                     }
 
-                    property.writeProperty(target, null, targetCollection);
+                    property.writePropertyDirectly(target, null, targetCollection);
                 }
 
                 return true;

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/DataObjectSerializationTest.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/DataObjectSerializationTest.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/DataObjectSerializationTest.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/DataObjectSerializationTest.java Sat Nov 25 17:37:41 2006
@@ -68,7 +68,7 @@
     }
 
     public void testSerializeNewWithFaults() throws Exception {
-        DataContext context = super.createDataContext();
+        DataContext context = createDataContext();
         Artist artist = (Artist) context.newObject("Artist");
         artist.setArtistName("artist1");
 

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/access/DataContextSharedCacheTest.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/access/DataContextSharedCacheTest.java?view=diff&rev=479252&r1=479251&r2=479252
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/access/DataContextSharedCacheTest.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4/src/test/java/org/apache/cayenne/access/DataContextSharedCacheTest.java Sat Nov 25 17:37:41 2006
@@ -29,14 +29,13 @@
 import org.apache.art.Artist;
 import org.apache.art.Painting;
 import org.apache.cayenne.DataRow;
-import org.apache.cayenne.Fault;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.unit.MultiContextCase;
 import org.apache.cayenne.unit.util.ThreadedTestHelper;
 
@@ -506,10 +505,12 @@
         ThreadedTestHelper helper = new ThreadedTestHelper() {
 
             protected void assertResult() throws Exception {
-                assertTrue(altArtist.readPropertyDirectly("paintingArray") instanceof Fault);
+                Object value = altArtist.readPropertyDirectly("paintingArray"); 
+                assertTrue("Unexpected: " + value, value instanceof ToManyList);
+                assertTrue(((ToManyList) value).isFault());
             }
         };
-        helper.assertWithTimeout(3000);
+        helper.assertWithTimeout(2000);
         List list = altArtist.getPaintingArray();
         assertEquals(2, list.size());
     }