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());