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 2011/09/04 02:54:53 UTC
svn commit: r1164952 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/ main/java/org/apache/cayenne/query/
test/java/org/apache/cayenne/ test/java/org/apache/cayenne/access/
Author: aadamchik
Date: Sun Sep 4 00:54:53 2011
New Revision: 1164952
URL: http://svn.apache.org/viewvc?rev=1164952&view=rev
Log:
CAY-1611 ObjectContext API improvement - better 'localObect' method
new end user method
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java
Modified:
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/query/ObjectIdQuery.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java
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=1164952&r1=1164951&r2=1164952&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 Sep 4 00:54:53 2011
@@ -21,7 +21,6 @@ package org.apache.cayenne;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -204,6 +203,72 @@ public abstract class BaseContext implem
this.entityResolver = entityResolver;
}
+ /**
+ * @since 3.1
+ */
+ public <T> T localObject(T objectFromAnotherContext) {
+
+ if (objectFromAnotherContext == null) {
+ throw new NullPointerException("Null object argument");
+ }
+
+ ObjectId id = ((Persistent) objectFromAnotherContext).getObjectId();
+
+ // first look for the ID in the local GraphManager
+ T localObject = (T) getGraphManager().getNode(id);
+ if (localObject != null) {
+ 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 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();
+
+ persistent.setObjectContext(this);
+ persistent.setObjectId(id);
+ persistent.setPersistenceState(PersistenceState.HOLLOW);
+
+ getGraphManager().registerNode(id, persistent);
+
+ return (T) persistent;
+ }
+ }
+
+ // 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?)
+
+ // 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);
+
+ localObject = (T) Cayenne.objectForQuery(this, query);
+ if (localObject != null) {
+ return localObject;
+ }
+
+ // 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();
public abstract Persistent localObject(ObjectId id, Object prototype);
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=1164952&r1=1164951&r2=1164952&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 Sep 4 00:54:53 2011
@@ -73,10 +73,24 @@ public interface ObjectContext extends S
* context) and "synchronization" (i.e. updating the state of the found object with
* the state of the prototype object).
* </p>
+ *
+ * @deprecated since 3.1 Cayenne users should use {@link #localObject(Object)}; the
+ * internal code has been refactored to avoid using this method all
+ * together.
*/
Persistent localObject(ObjectId id, Object prototype);
/**
+ * Returns a copy of 'objectFromAnotherContext' object that is registered in this
+ * context, creating and registering a local hollow object if needed. No DB query is
+ * performed. This method will cause an exception if an object is not already
+ * registered in this context or its parent DataChannel and the ObjectId is temporary.
+ *
+ * @since 3.1
+ */
+ <T> T localObject(T objectFromAnotherContext);
+
+ /**
* Creates a new persistent object of a given class scheduled to be inserted to the
* database on next commit.
*/
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/ObjectIdQuery.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/ObjectIdQuery.java?rev=1164952&r1=1164951&r2=1164952&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/ObjectIdQuery.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/ObjectIdQuery.java Sun Sep 4 00:54:53 2011
@@ -58,7 +58,7 @@ public class ObjectIdQuery extends Indir
}
/**
- * Creates a refreshing SingleObjectQuery.
+ * Creates a refreshing ObjectIdQuery.
*/
public ObjectIdQuery(ObjectId objectID) {
this(objectID, false, CACHE_REFRESH);
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java?rev=1164952&r1=1164951&r2=1164952&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java Sun Sep 4 00:54:53 2011
@@ -53,10 +53,17 @@ public class MockObjectContext implement
return graphManager;
}
+ /**
+ * @deprecated since 3.1
+ */
public Persistent localObject(ObjectId id, Object prototype) {
return null;
}
+ public <T> T localObject(T objectFromAnotherContext) {
+ return null;
+ }
+
public void commitChangesToParent() {
}
@@ -98,7 +105,7 @@ public class MockObjectContext implement
public void deleteObjects(Collection<?> objects) {
}
-
+
public void deleteObjects(Object... objects) throws DeleteDenyException {
}
@@ -149,7 +156,7 @@ public class MockObjectContext implement
public void invalidateObjects(Collection<?> objects) {
}
-
+
public void invalidateObjects(Object... objects) {
}
Added: 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=1164952&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataContextLocalObjectTest.java Sun Sep 4 00:54:53 2011
@@ -0,0 +1,150 @@
+/*****************************************************************
+ * 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.access;
+
+import org.apache.cayenne.Cayenne;
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextLocalObjectTest extends ServerCase {
+
+ @Inject
+ private DataContext context1;
+
+ @Inject
+ private DataContext context2;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ private DataChannelInterceptor interceptor;
+
+ @Inject
+ private ServerRuntime runtime;
+
+ private TableHelper tArtist;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTIST");
+ dbHelper.deleteAll("EXHIBIT");
+ dbHelper.deleteAll("GALLERY");
+
+ tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+ }
+
+ public void testLocalObject_InCache() throws Exception {
+ tArtist.insert(456, "Bla");
+
+ final Artist a1 = Cayenne.objectForPK(context1, Artist.class, 456);
+ final Artist a2 = Cayenne.objectForPK(context2, Artist.class, 456);
+
+ interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ Artist a3 = context2.localObject(a1);
+ assertSame(a3, a2);
+ assertSame(context2, a3.getObjectContext());
+ }
+ });
+ }
+
+ public void testLocalObject_SameContext() throws Exception {
+ tArtist.insert(456, "Bla");
+
+ final Artist a1 = Cayenne.objectForPK(context1, Artist.class, 456);
+
+ interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ Artist a2 = context1.localObject(a1);
+ assertSame(a2, a1);
+ }
+ });
+ }
+
+ public void testLocalObject_NotInCache() throws Exception {
+ tArtist.insert(456, "Bla");
+
+ final Artist a1 = Cayenne.objectForPK(context1, Artist.class, 456);
+
+ interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+ Artist a3 = context2.localObject(a1);
+ assertNotSame(a3, a1);
+ assertEquals(a3.getObjectId(), a1.getObjectId());
+ assertSame(context2, a3.getObjectContext());
+ }
+ });
+ }
+
+ public void testLocalObject_TempId() throws Exception {
+
+ final Artist a1 = context1.newObject(Artist.class);
+
+ interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ try {
+ context2.localObject(a1);
+ fail("returned a local object for temp ID");
+ }
+ catch (CayenneRuntimeException e) {
+ // expected
+ }
+ }
+ });
+ }
+
+ public void testLocalObject_TempId_NestedContext() throws Exception {
+
+ final Artist a1 = context1.newObject(Artist.class);
+
+ final ObjectContext nestedContext = runtime.getContext(context1);
+
+ interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+ public void execute() {
+
+ Artist a3 = nestedContext.localObject(a1);
+ assertNotSame(a3, a1);
+ assertEquals(a3.getObjectId(), a1.getObjectId());
+ assertSame(nestedContext, a3.getObjectContext());
+ }
+ });
+ }
+}