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 2012/01/22 09:13:34 UTC

svn commit: r1234462 - in /cayenne/main/trunk: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ framework/cayenne-jdk1.5-un...

Author: aadamchik
Date: Sun Jan 22 08:13:33 2012
New Revision: 1234462

URL: http://svn.apache.org/viewvc?rev=1234462&view=rev
Log:
CAY-1561 ObjectContext.localObject - defer FaultFailureExceptions on temporary IDs

Modified:
    cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/BaseContext.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContext.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/NestedDataContextPeerEventsTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java

Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Sun Jan 22 08:13:33 2012
@@ -27,6 +27,7 @@ CAY-1640 NullPointerException when savin
 CAY-1642 [PATCH] add ability to customize connection "timeout" setting for ROP
 CAY-1643 Updated Velocity templates to use static keys in setters/getters
 CAY-1649 Use BOOLEAN data type on Derby. Require Derby version >= 10.7.1.1.
+CAY-1651 ObjectContext.localObject - defer FaultFailureExceptions on temporary IDs
 
 Bug Fixes Since 3.1M3:
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/BaseContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/BaseContext.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/BaseContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/BaseContext.java Sun Jan 22 08:13:33 2012
@@ -242,53 +242,31 @@ public abstract class BaseContext implem
             return localObject;
         }
 
-        // if the ID is not temporary, let's optimistically assume it exists in the DB,
-        // and return a hollow object ... avoid race condition by synchronizing object
-        // creation and inserting
-        if (!id.isTemporary()) {
-            synchronized (getGraphManager()) {
-
-                // check for race condition - the object may have appeared in the
-                // GraphManager just recently...
-                localObject = (T) getGraphManager().getNode(id);
-                if (localObject != null) {
-                    return localObject;
-                }
-
-                // create a hollow object
-
-                ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(
-                        id.getEntityName());
-                Persistent persistent = (Persistent) descriptor.createObject();
+        synchronized (getGraphManager()) {
 
-                persistent.setObjectContext(this);
-                persistent.setObjectId(id);
-                persistent.setPersistenceState(PersistenceState.HOLLOW);
+            // check for race condition - the object may have appeared in the
+            // GraphManager just recently...
+            localObject = (T) getGraphManager().getNode(id);
+            if (localObject != null) {
+                return localObject;
+            }
 
-                getGraphManager().registerNode(id, persistent);
+            // create a hollow object, optimistically assuming that the ID we got from
+            // 'objectFromAnotherContext' is a valid ID either in the parent context or in
+            // the DB. This essentially defers possible FaultFailureExceptions.
 
-                return (T) persistent;
-            }
-        }
+            ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(
+                    id.getEntityName());
+            Persistent persistent = (Persistent) descriptor.createObject();
 
-        // if the ID is temporary, we still have a chance of finding the object in the
-        // parent channel (not sure if that's a good strategy with ROP?)
+            persistent.setObjectContext(this);
+            persistent.setObjectId(id);
+            persistent.setPersistenceState(PersistenceState.HOLLOW);
 
-        // note that since the query is configured to only hit the cache and avoid going
-        // to DB, it will not throw, but rather return NULL if the object we are looking
-        // for is not found.
-        ObjectIdQuery query = new ObjectIdQuery(id, false, ObjectIdQuery.CACHE_NOREFRESH);
+            getGraphManager().registerNode(id, persistent);
 
-        localObject = (T) Cayenne.objectForQuery(this, query);
-        if (localObject != null) {
-            return localObject;
+            return (T) persistent;
         }
-
-        // giving up...
-        throw new CayenneRuntimeException("A temporary ObjectId "
-                + id
-                + " was not found in the context and parent caches, "
-                + "so local version of the object can not be created.");
     }
 
     public abstract GraphManager getGraphManager();

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContext.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContext.java Sun Jan 22 08:13:33 2012
@@ -86,9 +86,8 @@ public interface ObjectContext extends S
      * previously cached in this context, a hollow object is created and returned to the
      * caller. No DB query is performed to resolve an object.
      * <p>
-     * This method will cause an exception if 'objectFromAnotherContext' has a temporary
-     * ObjectId and a copy of an object can't be found in this context or its parent
-     * DataChannel.
+     * Note that passing an object with a non-existing id, may later result in
+     * FaultFailureException on attempt to read returned object properties.
      * 
      * @since 3.1
      */

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java Sun Jan 22 08:13:33 2012
@@ -145,6 +145,16 @@ class DataDomainQueryAction implements Q
         if (query instanceof ObjectIdQuery) {
 
             ObjectIdQuery oidQuery = (ObjectIdQuery) query;
+            ObjectId oid = oidQuery.getObjectId();
+
+            // special handling of temp ids... Return an empty list immediately so that
+            // upstream code could throw FaultFailureException, etc. Don't attempt to
+            // translate and run the query. See for instance CAY-1651
+            if (oid.isTemporary() && !oid.isReplacementIdAttached()) {
+                response = new ListResponse();
+                return DONE;
+            }
+
             DataRow row = null;
 
             if (cache != null && !oidQuery.isFetchMandatory()) {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneTest.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/CayenneTest.java Sun Jan 22 08:13:33 2012
@@ -193,17 +193,9 @@ public class CayenneTest extends ServerC
         assertSame(o1, Cayenne.objectForPK(context, o1.getObjectId()));
         assertSame(o2, Cayenne.objectForPK(context, o2.getObjectId()));
 
-        try {
-            assertNull(Cayenne.objectForPK(context, new ObjectId("Artist", new byte[] {
-                    1, 2, 3
-            })));
-
-            fail("An attempt to fetch an object for "
-                    + "the non-existent temp id should have failed...");
-        }
-        catch (CayenneRuntimeException e) {
-            // expected
-        }
+        assertNull(Cayenne.objectForPK(context, new ObjectId("Artist", new byte[] {
+                1, 2, 3
+        })));
     }
 
     public void testObjectForPKObjectId() throws Exception {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java Sun Jan 22 08:13:33 2012
@@ -19,8 +19,9 @@
 package org.apache.cayenne.access;
 
 import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.FaultFailureException;
 import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.test.jdbc.DBHelper;
@@ -111,6 +112,31 @@ public class DataContextLocalObjectTest 
         });
     }
 
+    public void testLocalObject_FFE_InvalidID() throws Exception {
+        tArtist.insert(777, "AA");
+
+        final Artist a1 = Cayenne.objectForPK(context1, Artist.class, 777);
+
+        Artist a3 = context2.localObject(a1);
+        assertEquals(PersistenceState.HOLLOW, a3.getPersistenceState());
+
+        context1.invalidateObjects(a1);
+        tArtist.deleteAll();
+
+        assertEquals(PersistenceState.HOLLOW, a3.getPersistenceState());
+
+        try {
+            a3.getArtistName();
+
+            fail("FaultFailureException wasn't thrown on attempt to "
+                    + "resolve HOLLOW object with no backing DB row");
+        }
+        catch (FaultFailureException e) {
+            // expected
+        }
+
+    }
+
     public void testLocalObject_TempId() throws Exception {
 
         final Artist a1 = context1.newObject(Artist.class);
@@ -119,11 +145,18 @@ public class DataContextLocalObjectTest 
 
             public void execute() {
 
+                Artist a = context2.localObject(a1);
+                assertNotNull(a);
+                assertEquals(a1.getObjectId(), a.getObjectId());
+
+                // FFE mist be thrown on attempt to read non-existing temp ID
                 try {
-                    context2.localObject(a1);
-                    fail("returned a local object for temp ID");
+
+                    a.getArtistName();
+                    fail("FaultFailureException wasn't thrown on attempt to "
+                            + "resolve HOLLOW object with temp id");
                 }
-                catch (CayenneRuntimeException e) {
+                catch (FaultFailureException e) {
                     // expected
                 }
             }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/NestedDataContextPeerEventsTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/NestedDataContextPeerEventsTest.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/NestedDataContextPeerEventsTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/NestedDataContextPeerEventsTest.java Sun Jan 22 08:13:33 2012
@@ -41,11 +41,7 @@ public class NestedDataContextPeerEvents
 
         ObjectContext peer1 = runtime.getContext(context);
         Artist a1 = peer1.newObject(Artist.class);
-        a1.setArtistName("Z");
-
-        // commit to parent, so that object with temp ID becomes visible to peer child
-        // contexts
-        peer1.commitChangesToParent();
+        a1.setArtistName("Y");
 
         ObjectId a1TempId = a1.getObjectId();
         assertTrue(a1TempId.isTemporary());
@@ -55,9 +51,6 @@ public class NestedDataContextPeerEvents
 
         assertEquals(a1TempId, a2.getObjectId());
 
-        // make changes to be able to trigger a commit from child, the commit to DB
-        a1.setArtistName("Y");
-
         peer1.commitChanges();
         assertFalse(a1.getObjectId().isTemporary());
         assertFalse(a2.getObjectId().isTemporary());

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java?rev=1234462&r1=1234461&r2=1234462&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java Sun Jan 22 08:13:33 2012
@@ -47,16 +47,12 @@ public class NestedObjectContextPeerEven
         ClientMtTable1 a1 = peer1.newObject(ClientMtTable1.class);
         a1.setGlobalAttribute1("Y");
         ObjectId a1TempId = a1.getObjectId();
-        
-        // make sure temp ObjectId becomes available to peers
-        peer1.commitChangesToParent();
 
         ObjectContext peer2 = clientContext.createChildContext();
         ClientMtTable1 a2 = peer2.localObject(a1);
 
         assertEquals(a1TempId, a2.getObjectId());
 
-        a1.setGlobalAttribute1("Z");
         peer1.commitChanges();
         assertFalse(a1.getObjectId().isTemporary());
         assertFalse(a2.getObjectId().isTemporary());