cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject 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/
Date Sun, 04 Sep 2011 00:54:53 GMT
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());
+            }
+        });
+    }
+}



Mime
View raw message