You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by an...@apache.org on 2008/12/09 17:39:57 UTC
svn commit: r724771 - in
/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src:
main/java/org/apache/cayenne/ main/java/org/apache/cayenne/access/
test/java/org/apache/cayenne/ test/java/org/apache/cayenne/remote/
Author: andrey
Date: Tue Dec 9 08:39:56 2008
New Revision: 724771
URL: http://svn.apache.org/viewvc?rev=724771&view=rev
Log:
CAY-1119 Nested contexts on ROP
API changes
Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextLocalTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextParentEventsTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextRollbackTest.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextTest.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/CayenneContext.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextGraphManager.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextMergeHandler.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/ChildDiffLoader.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockObjectContext.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCayenneCase.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=724771&r1=724770&r2=724771&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 Tue Dec 9 08:39:56 2008
@@ -24,10 +24,15 @@
import org.apache.cayenne.cache.MapQueryCache;
import org.apache.cayenne.cache.QueryCache;
+import org.apache.cayenne.event.EventManager;
+import org.apache.cayenne.graph.CompoundDiff;
+import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.graph.GraphEvent;
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.query.ObjectIdQuery;
import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.RefreshQuery;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.ClassDescriptor;
import org.apache.cayenne.reflect.Property;
@@ -40,7 +45,7 @@
*
* @since 3.0
*/
-public abstract class BaseContext implements ObjectContext {
+public abstract class BaseContext implements ObjectContext, DataChannel {
/**
* A holder of a ObjectContext bound to the current thread.
@@ -118,6 +123,7 @@
* @deprecated since 3.0 this method is replaced by
* {@link #prepareForAccess(Persistent, String, boolean)}.
*/
+ @Deprecated
public void prepareForAccess(Persistent object, String property) {
prepareForAccess(object, property, false);
}
@@ -260,4 +266,88 @@
public synchronized void setQueryCache(QueryCache queryCache) {
this.queryCache = queryCache;
}
-}
+
+ /**
+ * Returns EventManager associated with the ObjectStore.
+ *
+ * @since 1.2
+ */
+ public EventManager getEventManager() {
+ return channel != null ? channel.getEventManager() : null;
+ }
+
+ public GraphDiff onSync(
+ ObjectContext originatingContext,
+ GraphDiff changes,
+ int syncType) {
+ switch (syncType) {
+ case DataChannel.ROLLBACK_CASCADE_SYNC:
+ return onContextRollback(originatingContext);
+ case DataChannel.FLUSH_NOCASCADE_SYNC:
+ return onContextFlush(originatingContext, changes, false);
+ case DataChannel.FLUSH_CASCADE_SYNC:
+ return onContextFlush(originatingContext, changes, true);
+ default:
+ throw new CayenneRuntimeException("Unrecognized SyncMessage type: "
+ + syncType);
+ }
+ }
+
+ GraphDiff onContextRollback(ObjectContext originatingContext) {
+ rollbackChanges();
+ return new CompoundDiff();
+ }
+
+ protected abstract GraphDiff onContextFlush(
+ ObjectContext originatingContext,
+ GraphDiff changes,
+ boolean cascade);
+
+ /**
+ * @since 1.2
+ */
+ protected void fireDataChannelCommitted(Object postedBy, GraphDiff changes) {
+ EventManager manager = getEventManager();
+
+ if (manager != null) {
+ GraphEvent e = new GraphEvent(this, postedBy, changes);
+ manager.postEvent(e, DataChannel.GRAPH_FLUSHED_SUBJECT);
+ }
+ }
+
+ /**
+ * @since 1.2
+ */
+ protected void fireDataChannelRolledback(Object postedBy, GraphDiff changes) {
+ EventManager manager = getEventManager();
+
+ if (manager != null) {
+ GraphEvent e = new GraphEvent(this, postedBy, changes);
+ manager.postEvent(e, DataChannel.GRAPH_ROLLEDBACK_SUBJECT);
+ }
+ }
+
+ /**
+ * @since 1.2
+ */
+ protected void fireDataChannelChanged(Object postedBy, GraphDiff changes) {
+ EventManager manager = getEventManager();
+
+ if (manager != null) {
+ GraphEvent e = new GraphEvent(this, postedBy, changes);
+ manager.postEvent(e, DataChannel.GRAPH_CHANGED_SUBJECT);
+ }
+ }
+
+ /**
+ * "Invalidates" a Collection of persistent objects. This operation would remove each
+ * object's snapshot from cache and change object's state to HOLLOW. On the next
+ * access to this object, it will be refetched.
+ *
+ * @see #unregisterObjects(Collection)
+ * @see RefreshQuery
+ */
+ public void invalidateObjects(Collection objects) {
+ performGenericQuery(new RefreshQuery(objects));
+ }
+}
\ No newline at end of file
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContext.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContext.java Tue Dec 9 08:39:56 2008
@@ -24,7 +24,9 @@
import java.util.Iterator;
import java.util.List;
+import org.apache.cayenne.access.ChildDiffLoader;
import org.apache.cayenne.event.EventManager;
+import org.apache.cayenne.graph.CompoundDiff;
import org.apache.cayenne.graph.GraphDiff;
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.EntityResolver;
@@ -223,9 +225,10 @@
graphManager.graphCommitStarted();
+ GraphDiff changes = graphManager.getDiffsSinceLastFlush();
+
try {
- commitDiff = channel.onSync(this, graphManager
- .getDiffsSinceLastFlush(), syncType);
+ commitDiff = channel.onSync(this, changes, syncType);
}
catch (Throwable th) {
graphManager.graphCommitAborted();
@@ -239,6 +242,10 @@
}
graphManager.graphCommitted(commitDiff);
+
+ // this event is caught by peer nested ObjectContexts to synchronize the
+ // state
+ fireDataChannelCommitted(this, changes);
}
}
@@ -259,6 +266,7 @@
graphManager.graphReverted();
channel.onSync(this, diff, DataChannel.ROLLBACK_CASCADE_SYNC);
+ fireDataChannelRolledback(this, diff);
}
}
}
@@ -267,7 +275,10 @@
public void rollbackChangesLocally() {
synchronized (graphManager) {
if (graphManager.hasChanges()) {
+ GraphDiff diff = graphManager.getDiffs();
graphManager.graphReverted();
+
+ fireDataChannelRolledback(this, diff);
}
}
}
@@ -333,9 +344,7 @@
return onQuery(this, query);
}
- // TODO: Andrus, 2/2/2006 - make public once CayenneContext is officially declared to
- // support DataChannel API.
- QueryResponse onQuery(ObjectContext context, Query query) {
+ public QueryResponse onQuery(ObjectContext context, Query query) {
return new CayenneContextQueryAction(this, context, query).execute();
}
@@ -410,7 +419,8 @@
getGraphManager().registerNode(id, localObject);
- if (prototype != null) {
+ if (prototype != null
+ && ((Persistent) prototype).getPersistenceState() != PersistenceState.HOLLOW) {
localObject.setPersistenceState(PersistenceState.COMMITTED);
descriptor.shallowMerge(prototype, localObject);
}
@@ -471,17 +481,24 @@
Persistent object,
String entityName,
ClassDescriptor descriptor) {
- ObjectId id = new ObjectId(entityName);
+ /**
+ * We should create new id only if it is not set for this object.
+ * It could have been created, for instance, in child context
+ */
+ ObjectId id = object.getObjectId();
+ if (id == null) {
+ id = new ObjectId(entityName);
+ object.setObjectId(id);
+ }
// must follow this exact order of property initialization per CAY-653, i.e. have
// the id and the context in place BEFORE setPersistence is called
- object.setObjectId(id);
object.setObjectContext(this);
object.setPersistenceState(PersistenceState.NEW);
synchronized (graphManager) {
- graphManager.registerNode(object.getObjectId(), object);
- graphManager.nodeCreated(object.getObjectId());
+ graphManager.registerNode(id, object);
+ graphManager.nodeCreated(id);
}
}
@@ -516,4 +533,64 @@
void setPropertyChangeCallbacksDisabled(boolean propertyChangeCallbacksDisabled) {
this.propertyChangeCallbacksDisabled = propertyChangeCallbacksDisabled;
}
+
+ /**
+ * Creates and returns a new child ObjectContext.
+ *
+ * @since 3.0
+ */
+ public ObjectContext createChildObjectContext() {
+ return new CayenneContext(this, graphManager.changeEventsEnabled,
+ graphManager.lifecycleEventsEnabled);
+ }
+
+ @Override
+ protected GraphDiff onContextFlush(
+ ObjectContext originatingContext,
+ GraphDiff changes,
+ boolean cascade) {
+
+ boolean childContext = this != originatingContext && changes != null;
+
+ if (childContext) {
+ changes.apply(new CayenneContextChildDiffLoader(this));
+ fireDataChannelChanged(originatingContext, changes);
+ }
+
+ return (cascade) ? doCommitChanges(true) : new CompoundDiff();
+ }
+
+ /**
+ * Returns <code>true</code> if there are any modified, deleted or new objects
+ * registered with this CayenneContext, <code>false</code> otherwise.
+ */
+ public boolean hasChanges() {
+ return graphManager.hasChanges();
+ }
+
+ /**
+ * Class for loading child's CayenneContext changes to parent context.
+ * Required to register diffs in CayenneContext's graph manager when node's simple property changes:
+ * CayenneContext's way of setting properties differs from DataContext's, and method of notifying
+ * graph manager is sealed in every 'set' method of Cayenne Client Data Object class.
+ * So here we should notify graph manager too, so that objects's state will update and they will
+ * be marked as dirty.
+ */
+ class CayenneContextChildDiffLoader extends ChildDiffLoader {
+ public CayenneContextChildDiffLoader(ObjectContext context) {
+ super(context);
+ }
+
+ @Override
+ public void nodePropertyChanged(
+ Object nodeId,
+ String property,
+ Object oldValue,
+ Object newValue) {
+ super.nodePropertyChanged(nodeId, property, oldValue, newValue);
+
+ Persistent object = (Persistent) getGraphManager().getNode(nodeId);
+ propertyChanged(object, property, oldValue, newValue);
+ }
+ }
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextGraphManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextGraphManager.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextGraphManager.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextGraphManager.java Tue Dec 9 08:39:56 2008
@@ -135,19 +135,15 @@
}
remapTargets();
+
+ stateLog.graphCommitted();
+ reset();
if (lifecycleEventsEnabled) {
- GraphDiff diff = changeLog.getDiffsAfterMarker(COMMIT_MARKER);
-
- stateLog.graphCommitted();
- reset();
-
// include all diffs after the commit start marker.
- send(diff, DataChannel.GRAPH_FLUSHED_SUBJECT, context);
- }
- else {
- stateLog.graphCommitted();
- reset();
+ //We fire event as if it was posted by parent channel, so that
+ //nested contexts could catch it
+ context.fireDataChannelCommitted(context.getChannel(), parentSyncDiff);
}
}
@@ -238,7 +234,7 @@
reset();
if (lifecycleEventsEnabled) {
- send(diff, DataChannel.GRAPH_ROLLEDBACK_SUBJECT, context);
+ context.fireDataChannelRolledback(context, diff);
}
}
@@ -297,7 +293,7 @@
changeLog.addOperation(diff);
if (changeEventsEnabled) {
- send(diff, DataChannel.GRAPH_CHANGED_SUBJECT, context);
+ context.fireDataChannelChanged(context, diff);
}
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextMergeHandler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextMergeHandler.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextMergeHandler.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneContextMergeHandler.java Tue Dec 9 08:39:56 2008
@@ -104,10 +104,7 @@
void repostAfterMerge(GraphEvent originalEvent) {
// though the subject is CHANGE, "merge" events are really lifecycle.
if (context.isLifecycleEventsEnabled()) {
- context.internalGraphManager().send(
- originalEvent.getDiff(),
- DataChannel.GRAPH_CHANGED_SUBJECT,
- originalEvent.getSource());
+ context.fireDataChannelChanged(originalEvent.getSource(), originalEvent.getDiff());
}
}
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=724771&r1=724770&r2=724771&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 Tue Dec 9 08:39:56 2008
@@ -26,6 +26,7 @@
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.RefreshQuery;
/**
* A Cayenne object facade to a persistent store. Instances of ObjectContext are used in
@@ -113,6 +114,7 @@
/**
* @deprecated since 3.0 use {@link #prepareForAccess(Persistent, String, boolean)}.
*/
+ @Deprecated
void prepareForAccess(Persistent object, String property);
/**
@@ -172,4 +174,28 @@
* Returns an DataChannel used by this context.
*/
DataChannel getChannel();
+
+ /**
+ * Creates and returns a new child ObjectContext.
+ *
+ * @since 3.0
+ */
+ ObjectContext createChildObjectContext();
+
+ /**
+ * Returns <code>true</code> if there are any modified, deleted or new objects
+ * registered with this ObjectContext, <code>false</code> otherwise.
+ *
+ * @since 3.0
+ */
+ boolean hasChanges();
+
+ /**
+ * "Invalidates" a Collection of persistent objects. This operation would remove each
+ * object's snapshot from cache and change object's state to HOLLOW. On the next
+ * access to this object, it will be refetched.
+ *
+ * @see RefreshQuery
+ */
+ void invalidateObjects(Collection objects);
}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ChildDiffLoader.java Tue Dec 9 08:39:56 2008
@@ -42,12 +42,13 @@
import org.apache.cayenne.reflect.ToOneProperty;
/**
- * A GraphChangeHandler that loads child ObjectContext diffs into a parent DataContext.
+ * A GraphChangeHandler that loads child ObjectContext diffs into a parent ObjectContext.
* Graph node ids are expected to be ObjectIds.
+ * This class is made public since 3.0 to be used in ObjectContext synchronizing
*
* @since 1.2
*/
-class ChildDiffLoader implements GraphChangeHandler {
+public class ChildDiffLoader implements GraphChangeHandler {
static final ThreadLocal<Boolean> childDiffProcessing = new ThreadLocal<Boolean>() {
@@ -77,7 +78,7 @@
childDiffProcessing.set(flag);
}
- ChildDiffLoader(ObjectContext context) {
+ public ChildDiffLoader(ObjectContext context) {
this.context = context;
}
@@ -142,8 +143,8 @@
((ObjectId) nodeId).getEntityName());
setExternalChange(Boolean.TRUE);
- try {
- descriptor.getProperty(property).writeProperty(object, null, newValue);
+ try {
+ descriptor.getProperty(property).writeProperty(object, null, newValue);
}
catch (Exception e) {
throw new CayenneRuntimeException("Error setting property: " + property, e);
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContext.java Tue Dec 9 08:39:56 2008
@@ -51,7 +51,6 @@
import org.apache.cayenne.event.EventManager;
import org.apache.cayenne.graph.CompoundDiff;
import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.graph.GraphEvent;
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
@@ -64,7 +63,6 @@
import org.apache.cayenne.query.ObjectIdQuery;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.QueryMetadata;
-import org.apache.cayenne.query.RefreshQuery;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.ClassDescriptor;
import org.apache.cayenne.reflect.PropertyVisitor;
@@ -123,6 +121,7 @@
* @see org.apache.cayenne.conf.WebApplicationContextFilter
* @deprecated since 3.0, replaced by BaseContex#getThreadObjectContext().
*/
+ @Deprecated
public static DataContext getThreadDataContext() throws IllegalStateException {
return (DataContext) BaseContext.getThreadObjectContext();
}
@@ -135,6 +134,7 @@
* @since 1.1
* @deprecated since 3.0, replaced by BaseContex#getThreadObjectContext().
*/
+ @Deprecated
public static void bindThreadDataContext(DataContext context) {
BaseContext.bindThreadObjectContext(context);
}
@@ -255,10 +255,21 @@
}
/**
+ * Creates and returns a new child ObjectContext.
+ *
+ * @since 3.0
+ */
+ public ObjectContext createChildObjectContext() {
+ return createChildDataContext();
+ }
+
+ /**
* Creates and returns a new child DataContext.
*
* @since 1.2
+ * @deprecated since 3.0 use {@link #createChildObjectContext()}.
*/
+ @Deprecated
public DataContext createChildDataContext() {
DataContextFactory factory = getParentDataDomain().getDataContextFactory();
@@ -598,6 +609,7 @@
* deprecated. Use {@link #objectsFromDataRows(ClassDescriptor, List)}
* instead.
*/
+ @Deprecated
public List objectsFromDataRows(
ObjEntity entity,
List dataRows,
@@ -632,6 +644,7 @@
* @since 1.1
* @see DataRow
*/
+ @Deprecated
public List objectsFromDataRows(
Class<?> objectClass,
List<? extends DataRow> dataRows,
@@ -691,6 +704,7 @@
/**
* @deprecated since 3.0, use {@link #newObject(String)} instead.
*/
+ @Deprecated
public DataObject createAndRegisterNewObject(String objEntityName) {
return (DataObject) newObject(objEntityName);
}
@@ -766,6 +780,7 @@
* @since 1.1
* @deprecated since 3.0, use {@link #newObject(Class)} instead.
*/
+ @Deprecated
public DataObject createAndRegisterNewObject(Class objectClass) {
if (objectClass == null) {
throw new NullPointerException("DataObject class can't be null.");
@@ -907,18 +922,6 @@
}
/**
- * "Invalidates" a Collection of persistent objects. This operation would remove each
- * object's snapshot from cache and change object's state to HOLLOW. On the next
- * access to this object, it will be refetched.
- *
- * @see #unregisterObjects(Collection)
- * @see RefreshQuery
- */
- public void invalidateObjects(Collection objects) {
- performGenericQuery(new RefreshQuery(objects));
- }
-
- /**
* Schedules all objects in the collection for deletion on the next commit of this
* DataContext. Object's persistence state is changed to PersistenceState.DELETED;
* objects related to this object are processed according to delete rules, i.e.
@@ -969,6 +972,7 @@
* is more than one object is fetched.
* @deprecated since 3.0 use {@link ObjectIdQuery} with appropriate refresh settings.
*/
+ @Deprecated
public DataObject refetchObject(ObjectId oid) {
if (oid == null) {
@@ -1073,45 +1077,8 @@
flushToParent(true);
}
- /**
- * Returns EventManager associated with the ObjectStore.
- *
- * @since 1.2
- */
- public EventManager getEventManager() {
- return channel != null ? channel.getEventManager() : null;
- }
-
- /**
- * An implementation of a {@link DataChannel} method that is used by child contexts to
- * synchronize state with this context. Not intended for direct use.
- *
- * @since 1.2
- */
- public GraphDiff onSync(
- ObjectContext originatingContext,
- GraphDiff changes,
- int syncType) {
- // sync client changes
- switch (syncType) {
- case DataChannel.ROLLBACK_CASCADE_SYNC:
- return onContextRollback(originatingContext);
- case DataChannel.FLUSH_NOCASCADE_SYNC:
- return onContextFlush(originatingContext, changes, false);
- case DataChannel.FLUSH_CASCADE_SYNC:
- return onContextFlush(originatingContext, changes, true);
- default:
- throw new CayenneRuntimeException("Unrecognized SyncMessage type: "
- + syncType);
- }
- }
-
- GraphDiff onContextRollback(ObjectContext originatingContext) {
- rollbackChanges();
- return new CompoundDiff();
- }
-
- GraphDiff onContextFlush(
+ @Override
+ protected GraphDiff onContextFlush(
ObjectContext originatingContext,
GraphDiff changes,
boolean cascade) {
@@ -1452,42 +1419,6 @@
this.validatingObjectsOnCommit = flag;
}
- /**
- * @since 1.2
- */
- void fireDataChannelCommitted(Object postedBy, GraphDiff changes) {
- EventManager manager = getEventManager();
-
- if (manager != null) {
- GraphEvent e = new GraphEvent(this, postedBy, changes);
- manager.postEvent(e, DataChannel.GRAPH_FLUSHED_SUBJECT);
- }
- }
-
- /**
- * @since 1.2
- */
- void fireDataChannelRolledback(Object postedBy, GraphDiff changes) {
- EventManager manager = getEventManager();
-
- if (manager != null) {
- GraphEvent e = new GraphEvent(this, postedBy, changes);
- manager.postEvent(e, DataChannel.GRAPH_ROLLEDBACK_SUBJECT);
- }
- }
-
- /**
- * @since 1.2
- */
- void fireDataChannelChanged(Object postedBy, GraphDiff changes) {
- EventManager manager = getEventManager();
-
- if (manager != null) {
- GraphEvent e = new GraphEvent(this, postedBy, changes);
- manager.postEvent(e, DataChannel.GRAPH_CHANGED_SUBJECT);
- }
- }
-
// ---------------------------------------------
// Serialization Support
// ---------------------------------------------
@@ -1686,4 +1617,8 @@
}
}
}
+
+ protected void fireDataChannelChanged(Object postedBy, GraphDiff changes) {
+ super.fireDataChannelChanged(postedBy, changes);
+ }
}
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=724771&r1=724770&r2=724771&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 Tue Dec 9 08:39:56 2008
@@ -104,6 +104,7 @@
/**
* @deprecated since 3.0
*/
+ @Deprecated
public void prepareForAccess(Persistent persistent, String property) {
}
@@ -136,4 +137,19 @@
public QueryResponse performGenericQuery(Query queryPlan) {
return null;
}
+
+ public ObjectContext createChildObjectContext() {
+ return null;
+ }
+
+ public <T> T newObject(Class<T> persistentClass) {
+ return null;
+ }
+
+ public boolean hasChanges() {
+ return false;
+ }
+
+ public void invalidateObjects(Collection objects) {
+ }
}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextLocalTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextLocalTest.java?rev=724771&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextLocalTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextLocalTest.java Tue Dec 9 08:39:56 2008
@@ -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.remote;
+
+import java.util.List;
+
+import org.apache.cayenne.BaseContext;
+import org.apache.cayenne.query.QueryCacheStrategy;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+
+public class NestedObjectContextLocalTest extends RemoteCayenneCase {
+ public void testLocalCacheStaysLocal() {
+
+ SelectQuery query = new SelectQuery(ClientMtTable1.class);
+ query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
+
+ BaseContext child1 = (BaseContext) context.createChildObjectContext();
+
+ assertNull(child1.getQueryCache().get(
+ query.getMetaData(child1.getEntityResolver())));
+
+ assertNull(context.getQueryCache().get(
+ query.getMetaData(context.getEntityResolver())));
+
+ List<?> results = child1.performQuery(query);
+ assertSame(results, child1.getQueryCache().get(
+ query.getMetaData(child1.getEntityResolver())));
+
+ assertNull(context.getQueryCache().get(
+ query.getMetaData(context.getEntityResolver())));
+ }
+}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextParentEventsTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextParentEventsTest.java?rev=724771&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextParentEventsTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextParentEventsTest.java Tue Dec 9 08:39:56 2008
@@ -0,0 +1,45 @@
+/*****************************************************************
+ * 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.remote;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+
+public class NestedObjectContextParentEventsTest extends RemoteCayenneCase {
+
+ public void testParentUpdatedId() throws Exception {
+ deleteTestData();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 ac = child.newObject(ClientMtTable1.class);
+ ac.setGlobalAttribute1("X");
+ child.commitChangesToParent();
+
+ ClientMtTable1 ap = (ClientMtTable1) context.getGraphManager().getNode(ac.getObjectId());
+ assertNotNull(ap);
+
+ assertTrue(ap.getObjectId().isTemporary());
+ context.commitChanges();
+
+ assertFalse(ap.getObjectId().isTemporary());
+ assertEquals(ap.getObjectId(), ac.getObjectId());
+ }
+}
Added: 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=724771&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextPeerEventsTest.java Tue Dec 9 08:39:56 2008
@@ -0,0 +1,134 @@
+/*****************************************************************
+ * 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.remote;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+
+public class NestedObjectContextPeerEventsTest extends RemoteCayenneCase {
+
+ public void testPeerObjectUpdatedTempOID() throws Exception {
+ deleteTestData();
+
+ ObjectContext peer1 = context.createChildObjectContext();
+ ClientMtTable1 a1 = peer1.newObject(ClientMtTable1.class);
+ a1.setGlobalAttribute1("Y");
+ ObjectId a1TempId = a1.getObjectId();
+
+ ObjectContext peer2 = context.createChildObjectContext();
+ ClientMtTable1 a2 = (ClientMtTable1) peer2.localObject(a1TempId, a1);
+
+ assertEquals(a1TempId, a2.getObjectId());
+
+ peer1.commitChanges();
+ assertFalse(a1.getObjectId().isTemporary());
+ assertFalse(a2.getObjectId().isTemporary());
+ assertEquals(a2.getObjectId(), a1.getObjectId());
+ }
+
+ public void testPeerObjectUpdatedSimpleProperty() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 a = context.newObject(ClientMtTable1.class);
+ a.setGlobalAttribute1("X");
+ context.commitChanges();
+
+ ObjectContext peer1 = context.createChildObjectContext();
+ ClientMtTable1 a1 = (ClientMtTable1) peer1.localObject(a.getObjectId(), a);
+
+ ObjectContext peer2 = context.createChildObjectContext();
+ ClientMtTable1 a2 = (ClientMtTable1) peer2.localObject(a.getObjectId(), a);
+
+ a1.setGlobalAttribute1("Y");
+ assertEquals("X", a2.getGlobalAttribute1());
+ peer1.commitChangesToParent();
+ assertEquals("Y", a2.getGlobalAttribute1());
+
+ assertFalse("Peer data context became dirty on event processing", peer2
+ .hasChanges());
+ }
+
+ public void testPeerObjectUpdatedToOneRelationship() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 a = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 altA = context.newObject(ClientMtTable1.class);
+
+ ClientMtTable2 p = context.newObject(ClientMtTable2.class);
+ p.setTable1(a);
+ p.setGlobalAttribute("PPP");
+ a.setGlobalAttribute1("X");
+ altA.setGlobalAttribute1("Y");
+ context.commitChanges();
+
+ ObjectContext peer1 = context.createChildObjectContext();
+ ClientMtTable2 p1 = (ClientMtTable2) peer1.localObject(p.getObjectId(), p);
+ ClientMtTable1 altA1 = (ClientMtTable1) peer1.localObject(altA.getObjectId(), altA);
+
+ ObjectContext peer2 = context.createChildObjectContext();
+ ClientMtTable2 p2 = (ClientMtTable2) peer2.localObject(p.getObjectId(), p);
+ ClientMtTable1 altA2 = (ClientMtTable1) peer2.localObject(altA.getObjectId(), altA);
+ ClientMtTable1 a2 = (ClientMtTable1) peer2.localObject(a.getObjectId(), a);
+
+ p1.setTable1(altA1);
+ assertSame(a2, p2.getTable1());
+ peer1.commitChangesToParent();
+ assertEquals(altA2, p2.getTable1());
+
+ assertFalse("Peer data context became dirty on event processing", peer2
+ .hasChanges());
+ }
+
+ public void testPeerObjectUpdatedToManyRelationship() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 a = context.newObject(ClientMtTable1.class);
+ a.setGlobalAttribute1("X");
+
+ ClientMtTable2 px = context.newObject(ClientMtTable2.class);
+ px.setTable1(a);
+ px.setGlobalAttribute("PX");
+
+ ClientMtTable2 py = context.newObject(ClientMtTable2.class);
+ py.setGlobalAttribute("PY");
+
+ context.commitChanges();
+
+ ObjectContext peer1 = context.createChildObjectContext();
+ ClientMtTable2 py1 = (ClientMtTable2) peer1.localObject(py.getObjectId(), py);
+ ClientMtTable1 a1 = (ClientMtTable1) peer1.localObject(a.getObjectId(), a);
+
+ ObjectContext peer2 = context.createChildObjectContext();
+ ClientMtTable2 py2 = (ClientMtTable2) peer2.localObject(py.getObjectId(), py);
+ ClientMtTable1 a2 = (ClientMtTable1) peer2.localObject(a.getObjectId(), a);
+
+ a1.addToTable2Array(py1);
+ assertEquals(1, a2.getTable2Array().size());
+ assertFalse(a2.getTable2Array().contains(py2));
+ peer1.commitChangesToParent();
+ assertEquals(2, a2.getTable2Array().size());
+ assertTrue(a2.getTable2Array().contains(py2));
+
+ assertFalse("Peer data context became dirty on event processing", peer2
+ .hasChanges());
+ }
+}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextRollbackTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextRollbackTest.java?rev=724771&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextRollbackTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextRollbackTest.java Tue Dec 9 08:39:56 2008
@@ -0,0 +1,63 @@
+/*****************************************************************
+ * 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.remote;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+
+public class NestedObjectContextRollbackTest extends RemoteCayenneCase {
+
+ public void testRollbackChanges() {
+ ObjectContext child1 = context.createChildObjectContext();
+
+ assertFalse(context.hasChanges());
+ assertFalse(child1.hasChanges());
+
+ context.newObject(ClientMtTable1.class);
+ child1.newObject(ClientMtTable1.class);
+
+ assertTrue(context.hasChanges());
+ assertTrue(child1.hasChanges());
+
+ child1.rollbackChanges();
+ assertFalse(context.hasChanges());
+ assertFalse(child1.hasChanges());
+
+ context.rollbackChanges();
+ }
+
+ public void testRollbackChangesLocally() {
+ ObjectContext child1 = context.createChildObjectContext();
+
+ assertFalse(context.hasChanges());
+ assertFalse(child1.hasChanges());
+
+ context.newObject(ClientMtTable1.class);
+ child1.newObject(ClientMtTable1.class);
+
+ assertTrue(context.hasChanges());
+ assertTrue(child1.hasChanges());
+
+ child1.rollbackChangesLocally();
+ assertTrue(context.hasChanges());
+ assertFalse(child1.hasChanges());
+
+ context.rollbackChanges();
+ }
+}
Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextTest.java?rev=724771&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/NestedObjectContextTest.java Tue Dec 9 08:39:56 2008
@@ -0,0 +1,600 @@
+/*****************************************************************
+ * 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.remote;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cayenne.DataObjectUtils;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.query.ObjectIdQuery;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+
+/**
+ * Tests nested object contexts
+ */
+public class NestedObjectContextTest extends RemoteCayenneCase {
+ public void testChannels() {
+ ObjectContext child = context.createChildObjectContext();
+
+ assertNotNull(child);
+ assertSame(context, child.getChannel());
+
+ // second level of nesting
+ ObjectContext grandchild = child.createChildObjectContext();
+
+ assertNotNull(grandchild);
+ assertSame(child, grandchild.getChannel());
+ }
+
+ public void testLocalObjectSynchronize() throws Exception {
+ deleteTestData();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 committed = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 deleted = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 modified = context.newObject(ClientMtTable1.class);
+
+ context.commitChanges();
+
+ context.deleteObject(deleted);
+ modified.setGlobalAttribute1("a");
+
+ ClientMtTable1 _new = context.newObject(ClientMtTable1.class);
+
+ ClientMtTable1 hollow = (ClientMtTable1) context.localObject(new ObjectId("MtTable1"), null);
+
+ assertEquals(PersistenceState.HOLLOW, hollow.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
+ assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
+ assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
+ assertEquals(PersistenceState.NEW, _new.getPersistenceState());
+
+ blockQueries();
+
+ try {
+ Persistent newPeer = child.localObject(_new.getObjectId(), _new);
+
+ assertEquals(_new.getObjectId(), newPeer.getObjectId());
+ assertEquals(PersistenceState.COMMITTED, newPeer.getPersistenceState());
+
+ assertSame(child, newPeer.getObjectContext());
+ assertSame(context, _new.getObjectContext());
+
+ Persistent hollowPeer = child.localObject(hollow.getObjectId(), hollow);
+ assertEquals(PersistenceState.HOLLOW, hollowPeer.getPersistenceState());
+ assertEquals(hollow.getObjectId(), hollowPeer.getObjectId());
+ assertSame(child, hollowPeer.getObjectContext());
+ assertSame(context, hollow.getObjectContext());
+
+ Persistent committedPeer = child.localObject(committed.getObjectId(), committed);
+ assertEquals(PersistenceState.COMMITTED, committedPeer.getPersistenceState());
+ assertEquals(committed.getObjectId(), committedPeer.getObjectId());
+ assertSame(child, committedPeer.getObjectContext());
+ assertSame(context, committed.getObjectContext());
+
+ ClientMtTable1 modifiedPeer = (ClientMtTable1) child.localObject(modified.getObjectId(), modified);
+ assertEquals(PersistenceState.COMMITTED, modifiedPeer.getPersistenceState());
+ assertEquals(modified.getObjectId(), modifiedPeer.getObjectId());
+ assertEquals("a", modifiedPeer.getGlobalAttribute1());
+ assertSame(child, modifiedPeer.getObjectContext());
+ assertSame(context, modified.getObjectContext());
+
+ Persistent deletedPeer = child.localObject(deleted.getObjectId(), deleted);
+ assertEquals(PersistenceState.COMMITTED, deletedPeer.getPersistenceState());
+ assertEquals(deleted.getObjectId(), deletedPeer.getObjectId());
+ assertSame(child, deletedPeer.getObjectContext());
+ assertSame(context, deleted.getObjectContext());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testLocalObjectsNoOverride() throws Exception {
+ deleteTestData();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 modified = context.newObject(ClientMtTable1.class);
+ context.commitChanges();
+
+ ClientMtTable1 peerModified = (ClientMtTable1) DataObjectUtils.objectForQuery(
+ child, new ObjectIdQuery(modified.getObjectId()));
+
+ modified.setGlobalAttribute1("M1");
+ peerModified.setGlobalAttribute1("M2");
+
+ assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
+ assertEquals(PersistenceState.MODIFIED, peerModified.getPersistenceState());
+
+ blockQueries();
+
+ try {
+
+ Persistent peerModified2 = child.localObject(modified.getObjectId(), modified);
+ assertSame(peerModified, peerModified2);
+ assertEquals(PersistenceState.MODIFIED, peerModified2.getPersistenceState());
+ assertEquals("M2", peerModified.getGlobalAttribute1());
+ assertEquals("M1", modified.getGlobalAttribute1());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testLocalObjectRelationship() throws Exception {
+ deleteTestData();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 _new = context.newObject(ClientMtTable1.class);
+ ClientMtTable2 _new2 = context.newObject(ClientMtTable2.class);
+ _new.addToTable2Array(_new2);
+
+ blockQueries();
+
+ try {
+
+ ClientMtTable2 child2 = (ClientMtTable2) child.localObject(_new2.getObjectId(), _new2);
+ assertEquals(PersistenceState.COMMITTED, child2.getPersistenceState());
+ assertNotNull(child2.getTable1());
+ assertEquals(PersistenceState.COMMITTED, child2.getTable1().getPersistenceState());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testSelect() throws Exception {
+ deleteTestData();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 committed = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 deleted = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 modified = context.newObject(ClientMtTable1.class);
+
+ context.commitChanges();
+ int modifiedid = DataObjectUtils.intPKForObject(modified);
+
+ // test how different object states appear in the child on select
+
+ context.deleteObject(deleted);
+ modified.setGlobalAttribute1("a");
+
+ ClientMtTable1 _new = context.newObject(ClientMtTable1.class);
+
+ assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
+ assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
+ assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
+ assertEquals(PersistenceState.NEW, _new.getPersistenceState());
+
+ List objects = child.performQuery(new SelectQuery(ClientMtTable1.class));
+ assertEquals("All but NEW object must have been included", 3, objects.size());
+
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ ClientMtTable1 next = (ClientMtTable1) it.next();
+ assertEquals(PersistenceState.COMMITTED, next.getPersistenceState());
+
+ int id = DataObjectUtils.intPKForObject(next);
+ if (id == modifiedid) {
+ assertEquals("a", next.getGlobalAttribute1());
+ }
+ }
+ }
+
+ public void testPrefetchingToOne() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 mt11 = context.newObject(ClientMtTable1.class);
+ ClientMtTable1 mt12 = context.newObject(ClientMtTable1.class);
+ ClientMtTable2 mt21 = context.newObject(ClientMtTable2.class);
+ ClientMtTable2 mt22 = context.newObject(ClientMtTable2.class);
+
+ mt21.setTable1(mt11);
+ mt22.setTable1(mt11);
+
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ SelectQuery q = new SelectQuery(ClientMtTable2.class);
+ q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
+
+ List results = child.performQuery(q);
+
+ blockQueries();
+ try {
+ assertEquals(2, results.size());
+ Iterator it = results.iterator();
+ while (it.hasNext()) {
+ ClientMtTable2 o = (ClientMtTable2) it.next();
+ assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+ assertSame(child, o.getObjectContext());
+
+ ClientMtTable1 o1 = o.getTable1();
+ assertNotNull(o1);
+ assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+ assertSame(child, o1.getObjectContext());
+ assertEquals(mt11.getObjectId(), o1.getObjectId());
+ }
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testPrefetchingToMany() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 mt11 = context.newObject(ClientMtTable1.class);
+ mt11.setGlobalAttribute1("1");
+
+ ClientMtTable1 mt12 = context.newObject(ClientMtTable1.class);
+ mt12.setGlobalAttribute1("2");
+
+ ClientMtTable2 mt21 = context.newObject(ClientMtTable2.class);
+ ClientMtTable2 mt22 = context.newObject(ClientMtTable2.class);
+
+ mt21.setTable1(mt11);
+ mt22.setTable1(mt11);
+
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ SelectQuery q = new SelectQuery(ClientMtTable1.class);
+ q.addOrdering("globalAttribute1", true);
+ q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+
+ List results = child.performQuery(q);
+
+ blockQueries();
+ try {
+
+ ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
+ assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+ assertSame(child, o1.getObjectContext());
+
+ List<ClientMtTable2> children1 = o1.getTable2Array();
+
+ assertEquals(2, children1.size());
+ Iterator<ClientMtTable2> it = children1.iterator();
+ while (it.hasNext()) {
+ ClientMtTable2 o = it.next();
+ assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+ assertSame(child, o.getObjectContext());
+
+ assertEquals(o1, o.getTable1());
+ }
+
+ ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
+ assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+ assertSame(child, o2.getObjectContext());
+
+ List children2 = o2.getTable2Array();
+
+ assertEquals(0, children2.size());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testDeleteNew() throws Exception {
+ deleteTestData();
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 a = context.newObject(ClientMtTable1.class);
+ context.commitChanges();
+
+ ClientMtTable2 p = child.newObject(ClientMtTable2.class);
+ ClientMtTable1 aChild = (ClientMtTable1) DataObjectUtils.objectForPK(child, a.getObjectId());
+ p.setGlobalAttribute("X");
+ aChild.addToTable2Array(p);
+
+ child.commitChangesToParent();
+
+ child.deleteObject(p);
+ aChild.removeFromTable2Array(p);
+
+ child.commitChangesToParent();
+ }
+
+ /**
+ * A test case for CAY-698 bug.
+ */
+ public void testNullifyToOne() throws Exception {
+ deleteTestData();
+
+ ClientMtTable1 a = context.newObject(ClientMtTable1.class);
+ ClientMtTable2 b = context.newObject(ClientMtTable2.class);
+ a.addToTable2Array(b);
+
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+ ObjectContext childPeer = context.createChildObjectContext();
+
+ ClientMtTable2 childP1 = (ClientMtTable2) DataObjectUtils.objectForPK(child, b.getObjectId());
+
+ // trigger object creation in the peer nested DC
+ DataObjectUtils.objectForPK(childPeer, b.getObjectId());
+ childP1.setTable1(null);
+
+ blockQueries();
+
+ try {
+ child.commitChangesToParent();
+ assertEquals(PersistenceState.COMMITTED, childP1.getPersistenceState());
+
+ ClientMtTable2 parentP1 = (ClientMtTable2) context.getGraphManager().getNode(
+ childP1.getObjectId());
+
+ assertNotNull(parentP1);
+ assertEquals(PersistenceState.MODIFIED, parentP1.getPersistenceState());
+ assertNull(parentP1.getTable1());
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testCommitChangesToParent() throws Exception {
+ deleteTestData();
+
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ SelectQuery query = new SelectQuery(ClientMtTable1.class);
+ List objects = child.performQuery(query);
+
+ assertEquals(4, objects.size());
+
+ ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
+ childNew.setGlobalAttribute1("NNN");
+
+ ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
+ childModified.setGlobalAttribute1("MMM");
+
+ ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
+
+ ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
+ child.invalidateObjects(Collections.singleton(childHollow));
+
+ blockQueries();
+
+ try {
+ child.commitChangesToParent();
+
+ // * all modified child objects must be in committed state now
+ // * all modifications should be propagated to the parent
+ // * no actual commit should occur.
+
+ assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
+ assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
+
+ ClientMtTable1 parentNew = (ClientMtTable1) context.getGraphManager().getNode(
+ childNew.getObjectId());
+ ClientMtTable1 parentModified = (ClientMtTable1) context.getGraphManager().getNode(
+ childModified.getObjectId());
+ ClientMtTable1 parentCommitted = (ClientMtTable1) context.getGraphManager().getNode(
+ childCommitted.getObjectId());
+ ClientMtTable1 parentHollow = (ClientMtTable1) context.getGraphManager().getNode(
+ childHollow.getObjectId());
+
+ assertNotNull(parentNew);
+ assertEquals(PersistenceState.NEW, parentNew.getPersistenceState());
+ assertEquals("NNN", parentNew.getGlobalAttribute1());
+
+ assertNotNull(parentModified);
+ assertEquals(PersistenceState.MODIFIED, parentModified.getPersistenceState());
+ assertEquals("MMM", parentModified.getGlobalAttribute1());
+
+ assertNotNull(parentCommitted);
+ assertEquals(PersistenceState.COMMITTED, parentCommitted
+ .getPersistenceState());
+
+ assertNotNull(parentHollow);
+ }
+ finally {
+ unblockQueries();
+ }
+ }
+
+ public void testCommitChangesToParentDeleted() throws Exception {
+ deleteTestData();
+
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ // make sure we fetch in predictable order
+ SelectQuery query = new SelectQuery(ClientMtTable1.class);
+ List objects = child.performQuery(query);
+
+ assertEquals(4, objects.size());
+
+ // delete AND modify
+ ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
+ child.deleteObject(childDeleted);
+ childDeleted.setGlobalAttribute1("DDD");
+
+ // don't block queries - on delete Cayenne may need to resolve delete rules via
+ // fetch
+ child.commitChangesToParent();
+
+ // * all modified child objects must be in committed state now
+ // * all modifications should be propagated to the parent
+ // * no actual commit should occur.
+
+ assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
+
+ ClientMtTable1 parentDeleted = (ClientMtTable1) context.getGraphManager().getNode(
+ childDeleted.getObjectId());
+
+ assertNotNull(parentDeleted);
+ assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
+ assertEquals("DDD", parentDeleted.getGlobalAttribute1());
+ }
+
+ public void testCommitChanges() throws Exception {
+ deleteTestData();
+
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.newObject(ClientMtTable1.class);
+ context.commitChanges();
+
+ ObjectContext child = context.createChildObjectContext();
+
+ // make sure we fetch in predictable order
+ SelectQuery query = new SelectQuery(ClientMtTable1.class);
+ List objects = child.performQuery(query);
+
+ assertEquals(4, objects.size());
+
+ ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
+ childNew.setGlobalAttribute1("NNN");
+
+ ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
+ childModified.setGlobalAttribute1("MMM");
+
+ ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
+
+ // delete AND modify
+ ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
+ child.deleteObject(childDeleted);
+ childDeleted.setGlobalAttribute1("DDD");
+
+ ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
+ child.invalidateObjects(Collections.singleton(childHollow));
+
+ child.commitChanges();
+
+ assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
+ assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
+ assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
+ assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
+
+ ClientMtTable1 parentNew = (ClientMtTable1) context.getGraphManager().getNode(
+ childNew.getObjectId());
+ ClientMtTable1 parentModified = (ClientMtTable1) context.getGraphManager().getNode(
+ childModified.getObjectId());
+ ClientMtTable1 parentCommitted = (ClientMtTable1) context.getGraphManager().getNode(
+ childCommitted.getObjectId());
+ ClientMtTable1 parentDeleted = (ClientMtTable1) context.getGraphManager().getNode(
+ childDeleted.getObjectId());
+ ClientMtTable1 parentHollow = (ClientMtTable1) context.getGraphManager().getNode(
+ childHollow.getObjectId());
+
+ assertNotNull(parentNew);
+ assertEquals(PersistenceState.COMMITTED, parentNew.getPersistenceState());
+ assertEquals("NNN", parentNew.getGlobalAttribute1());
+
+ assertNotNull(parentModified);
+ assertEquals(PersistenceState.COMMITTED, parentModified.getPersistenceState());
+ assertEquals("MMM", parentModified.getGlobalAttribute1());
+
+ assertNull("Deleted object should not be registered.", parentDeleted);
+
+ assertNotNull(parentCommitted);
+ assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
+
+ assertNotNull(parentHollow);
+ }
+
+ public void testAddRemove() throws Exception {
+ deleteTestData();
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 a = child.newObject(ClientMtTable1.class);
+ a.setGlobalAttribute1("X");
+ child.commitChanges();
+
+ ClientMtTable2 p1 = child.newObject(ClientMtTable2.class);
+ p1.setGlobalAttribute("P1");
+ a.addToTable2Array(p1);
+
+ ClientMtTable2 p2 = child.newObject(ClientMtTable2.class);
+ p2.setGlobalAttribute("P2");
+ a.addToTable2Array(p2);
+
+ a.removeFromTable2Array(p2);
+
+ // this causes an error on commit
+ child.deleteObject(p2);
+
+ child.commitChangesToParent();
+
+ }
+
+ public void testChangeRel() throws Exception {
+ deleteTestData();
+ ObjectContext child = context.createChildObjectContext();
+
+ ClientMtTable1 a = child.newObject(ClientMtTable1.class);
+ ClientMtTable2 b = child.newObject(ClientMtTable2.class);
+ child.commitChanges();
+
+ assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+
+ a.addToTable2Array(b);
+ assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
+
+ child.commitChangesToParent();
+ ClientMtTable1 parentA = (ClientMtTable1) context.getGraphManager().getNode(a.getObjectId());
+ assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+ assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
+ assertEquals(1, parentA.getTable2Array().size());
+
+ context.commitChanges();
+ assertEquals(PersistenceState.COMMITTED, parentA.getPersistenceState());
+
+ a.removeFromTable2Array(b);
+ assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
+
+ child.commitChangesToParent();
+ assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+ assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
+ assertEquals(0, parentA.getTable2Array().size());
+ }
+}
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCayenneCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCayenneCase.java?rev=724771&r1=724770&r2=724771&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCayenneCase.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCayenneCase.java Tue Dec 9 08:39:56 2008
@@ -33,10 +33,12 @@
public abstract class RemoteCayenneCase extends CayenneCase {
protected CayenneContext context;
+ protected DataContext parentDataContext;
+
@Override
public void setUp() throws Exception {
- DataContext dataContext = createDataContext();
- ClientServerChannel clientServerChannel = new ClientServerChannel(dataContext);
+ parentDataContext = createDataContext();
+ ClientServerChannel clientServerChannel = new ClientServerChannel(parentDataContext);
UnitLocalConnection connection = new UnitLocalConnection(
clientServerChannel,
LocalConnection.HESSIAN_SERIALIZATION);