FAQ
Andrey, after your commit I have this problem:

[INFO] Compilation failure
/home/olga/cayenne-git/framework/cayenne-tools/src/test/java/org/apache/cayenne/gen/ClientDataMapGeneratedQueryRunTest.java:[59,86]
incompatible types
found : java.util.List<org.apache.cayenne.testdo.mt.MtTable1>
required: java.util.List<org.apache.cayenne.testdo.mt.ClientMtTable1>

and reasonable error in cayenne-tools.


2009/11/18 <andrey@apache.org>
Author: andrey
Date: Wed Nov 18 12:08:20 2009
New Revision: 881740

URL: http://svn.apache.org/viewvc?rev=881740&view=rev
Log:
CAY-1312 Allow lifecycle callbacks on ROP client. Only method invokes, i.e.
no configuration for those callbacks yet

Added:

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
- copied, changed from r881253,
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
Removed:

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.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/ObjectContextDeleteAction.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/main/java/org/apache/cayenne/access/DataDomain.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java

cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml

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=881740&r1=881739&r2=881740&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
Wed Nov 18 12:08:20 2009
@@ -33,6 +33,7 @@
import org.apache.cayenne.graph.GraphEvent;
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.LifecycleEvent;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.query.ObjectIdQuery;
import org.apache.cayenne.query.Query;
@@ -103,8 +104,6 @@

public abstract void commitChangesToParent();

- public abstract void deleteObject(Object object) throws
DeleteDenyException;
-
public abstract Collection<?> deletedObjects();

public DataChannel getChannel() {
@@ -381,9 +380,24 @@
}

/**
- * If ObjEntity qualifier is set, asks it to inject initial value to
an object
+ * If ObjEntity qualifier is set, asks it to inject initial value to
an object.
+ * Also performs all Persistent initialization operations
*/
- protected void injectInitialValue(Object object) {
+ protected void injectInitialValue(Object obj) {
+ // 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
+
+ Persistent object = (Persistent) obj;
+
+ object.setObjectContext(this);
+ object.setPersistenceState(PersistenceState.NEW);
+
+ GraphManager graphManager = getGraphManager();
+ synchronized (graphManager) {
+ graphManager.registerNode(object.getObjectId(), object);
+ graphManager.nodeCreated(object.getObjectId());
+ }
+
ObjEntity entity;
try {
entity =
getEntityResolver().lookupObjEntity(object.getClass());
@@ -398,5 +412,37 @@
((ValueInjector)
entity.getDeclaredQualifier()).injectValue(object);
}
}
+
+ // invoke callbacks
+ getEntityResolver().getCallbackRegistry().performCallbacks(
+ LifecycleEvent.POST_ADD,
+ object);
+ }
+
+ /**
+ * Schedules an object for deletion on the next commit of this
context. Object's
+ * persistence state is changed to PersistenceState.DELETED; objects
related to this
+ * object are processed according to delete rules, i.e. relationships
can be unset
+ * ("nullify" rule), deletion operation is cascaded (cascade rule).
+ *
+ * @param object a persistent object that we want to delete.
+ * @throws DeleteDenyException if a DENY delete rule is applicable for
object
+ * deletion.
+ * @throws NullPointerException if object is null.
+ */
+ public void deleteObject(Object object) {
+ new ObjectContextDeleteAction(this).performDelete((Persistent)
object);
+ }
+
+ public void deleteObjects(Collection<?> objects) throws
DeleteDenyException {
+ if (objects.isEmpty())
+ return;
+
+ // Don't call deleteObject() directly since it would be less
efficient.
+ ObjectContextDeleteAction ocda = new
ObjectContextDeleteAction(this);
+
+ // Make a copy to iterate over to avoid
ConcurrentModificationException.
+ for (Persistent object : (ArrayList<Persistent>) new
ArrayList(objects))
+ ocda.performDelete(object);
}
}
\ 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=881740&r1=881739&r2=881740&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
Wed Nov 18 12:08:20 2009
@@ -308,27 +308,6 @@
}

/**
- * Deletes an object locally, scheduling it for future deletion from
the external data
- * store.
- */
- @Override
- public void deleteObject(Object object) {
- new ObjectContextDeleteAction(this).performDelete((Persistent)
object);
- }
-
- public void deleteObjects(Collection<?> objects) throws
DeleteDenyException {
- if (objects.isEmpty())
- return;
-
- // Don't call deleteObject() directly since it would be less
efficient.
- ObjectContextDeleteAction ocda = new
ObjectContextDeleteAction(this);
-
- // Make a copy to iterate over to avoid
ConcurrentModificationException.
- for (Persistent object : (ArrayList<Persistent>) new
ArrayList(objects))
- ocda.performDelete(object);
- }
-
- /**
* Creates and registers a new Persistent object instance.
*/
@Override
@@ -527,16 +506,6 @@
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.setObjectContext(this);
- object.setPersistenceState(PersistenceState.NEW);
-
- synchronized (graphManager) {
- graphManager.registerNode(id, object);
- graphManager.nodeCreated(id);
- }
-
injectInitialValue(object);
}


Copied:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
(from r881253,
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java)
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java?p2=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java&p1=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java&r1=881253&r2=881740&rev=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
Wed Nov 18 12:08:20 2009
@@ -16,14 +16,13 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.access;
+package org.apache.cayenne;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

-import org.apache.cayenne.DataChannel;
import org.apache.cayenne.graph.GraphChangeHandler;
import org.apache.cayenne.graph.GraphDiff;
import org.apache.cayenne.graph.GraphManager;
@@ -32,10 +31,11 @@

/**
* @since 3.0
+ * note: made public in 3.1 to be used in all tiers
*/
-abstract class DataChannelSyncCallbackAction implements GraphChangeHandler
{
+public abstract class DataChannelSyncCallbackAction implements
GraphChangeHandler {

- static DataChannelSyncCallbackAction getCallbackAction(
+ public static DataChannelSyncCallbackAction getCallbackAction(
LifecycleCallbackRegistry callbackRegistry,
GraphManager graphManager,
GraphDiff changes,
@@ -73,9 +73,9 @@

protected abstract boolean hasListeners();

- abstract void applyPreCommit();
+ public abstract void applyPreCommit();

- abstract void applyPostCommit();
+ public abstract void applyPostCommit();

void apply(LifecycleEvent callbackType, Collection<?> objects) {
if (seenIds != null && objects != null) {
@@ -166,13 +166,13 @@
}

@Override
- void applyPreCommit() {
+ public void applyPreCommit() {
apply(LifecycleEvent.PRE_PERSIST, persisted);
apply(LifecycleEvent.PRE_UPDATE, updated);
}

@Override
- void applyPostCommit() {
+ public void applyPostCommit() {
apply(LifecycleEvent.POST_UPDATE, updated);
apply(LifecycleEvent.POST_REMOVE, removed);
apply(LifecycleEvent.POST_PERSIST, persisted);
@@ -192,12 +192,12 @@
}

@Override
- void applyPreCommit() {
+ public void applyPreCommit() {
// noop
}

@Override
- void applyPostCommit() {
+ public void applyPostCommit() {
apply(LifecycleEvent.POST_LOAD, updated);
apply(LifecycleEvent.POST_LOAD, removed);
}

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
Wed Nov 18 12:08:20 2009
@@ -23,14 +23,14 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.Map;

import org.apache.cayenne.map.DeleteRule;
-import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.LifecycleEvent;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.reflect.ArcProperty;
import org.apache.cayenne.reflect.AttributeProperty;
import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.Property;
import org.apache.cayenne.reflect.PropertyVisitor;
import org.apache.cayenne.reflect.ToManyProperty;
import org.apache.cayenne.reflect.ToOneProperty;
@@ -54,6 +54,10 @@

if (oldState == PersistenceState.TRANSIENT
oldState == PersistenceState.DELETED) {
+ // Drop out... especially in case of DELETED we might be about
to get
+ // into a horrible recursive loop due to CASCADE delete rules.
+ // Assume that everything must have been done correctly
already
+ // and *don't* do it again
return false;
}

@@ -69,6 +73,11 @@
+ ", context: "
+ context);
}
+
+ // must resolve HOLLOW objects before delete... needed
+ // to process relationships and optimistic locking...
+
+ context.prepareForAccess(object, null, false);

if (oldState == PersistenceState.NEW) {
deleteNew(object);
@@ -80,133 +89,148 @@
return true;
}

- private void deleteNew(Persistent object) {
+ private void deleteNew(Persistent object) throws DeleteDenyException {
object.setPersistenceState(PersistenceState.TRANSIENT);
processDeleteRules(object, PersistenceState.NEW);
+
+ // if an object was NEW, we must throw it out
context.getGraphManager().unregisterNode(object.getObjectId());
}

- private void deletePersistent(Persistent object) {
+ private void deletePersistent(Persistent object) throws
DeleteDenyException {
+
context.getEntityResolver().getCallbackRegistry().performCallbacks(
+ LifecycleEvent.PRE_REMOVE,
+ object);
+
int oldState = object.getPersistenceState();
object.setPersistenceState(PersistenceState.DELETED);
processDeleteRules(object, oldState);
context.getGraphManager().nodeRemoved(object.getObjectId());
}

- private void processDeleteRules(final Persistent object, final int
oldState) {
+ private Collection toCollection(Object object) {

- String entityName = object.getObjectId().getEntityName();
- final ObjEntity entity =
context.getEntityResolver().getObjEntity(entityName);
- ClassDescriptor descriptor =
context.getEntityResolver().getClassDescriptor(
- entityName);
+ if (object == null) {
+ return Collections.EMPTY_LIST;
+ }

- descriptor.visitProperties(new PropertyVisitor() {
+ // create copies of collections to avoid iterator exceptions
+ if (object instanceof Collection) {
+ return new ArrayList((Collection) object);
+ }
+ else if (object instanceof Map) {
+ return new ArrayList(((Map) object).values());
+ }
+ else {
+ return Collections.singleton(object);
+ }
+ }

- public boolean visitToMany(ToManyProperty property) {
- ObjRelationship relationship = (ObjRelationship) entity
- .getRelationship(property.getName());
+ private void processDeleteRules(final Persistent object, int oldState)
+ throws DeleteDenyException {

- processRules(object, property,
relationship.getDeleteRule(), oldState);
- return true;
- }
+ ClassDescriptor descriptor =
context.getEntityResolver().getClassDescriptor(
+ object.getObjectId().getEntityName());

- public boolean visitToOne(ToOneProperty property) {
- ObjRelationship relationship = (ObjRelationship) entity
- .getRelationship(property.getName());
+ for (final ObjRelationship relationship :
descriptor.getEntity().getRelationships()) {

- processRules(object, property,
relationship.getDeleteRule(), oldState);
- return true;
- }
+ boolean processFlattened = relationship.isFlattened()
+ && relationship.isToDependentEntity()
+ && !relationship.isReadOnly();

- public boolean visitAttribute(AttributeProperty property) {
- return true;
+ // first check for no action... bail out if no flattened
processing is needed
+ if (relationship.getDeleteRule() == DeleteRule.NO_ACTION &&
!processFlattened) {
+ continue;
}
- });
- }
-
- private void processRules(
- Persistent object,
- ArcProperty property,
- int deleteRule,
- int oldState) {
-
- if (deleteRule == DeleteRule.NO_ACTION) {
- return;
- }
-
- Collection<?> relatedObjects = relatedObjects(object, property);
- if (relatedObjects.isEmpty()) {
- return;
- }

- switch (deleteRule) {
+ ArcProperty property = (ArcProperty)
descriptor.getProperty(relationship
+ .getName());
+ Collection relatedObjects =
toCollection(property.readProperty(object));
+
+ // no related object, bail out
+ if (relatedObjects.size() == 0) {
+ continue;
+ }

- case DeleteRule.DENY:
+ // process DENY rule first...
+ if (relationship.getDeleteRule() == DeleteRule.DENY) {
object.setPersistenceState(oldState);
+
String message = relatedObjects.size() == 1
? "1 related object"
: relatedObjects.size() + " related objects";
- throw new DeleteDenyException(object, property.getName(),
message);
-
- case DeleteRule.NULLIFY:
- ArcProperty reverseArc =
property.getComplimentaryReverseArc();
+ throw new DeleteDenyException(object,
relationship.getName(), message);
+ }

- if (reverseArc != null) {
+ // process flattened with dependent join tables...
+ // joins must be removed even if they are non-existent or
ignored in the
+ // object graph
+ if (processFlattened) {
+ Iterator iterator = relatedObjects.iterator();
+ while (iterator.hasNext()) {
+ Persistent relatedObject = (Persistent)
iterator.next();
+
context.getGraphManager().arcDeleted(object.getObjectId(), relatedObject
+ .getObjectId(), relationship.getName());
+ }
+ }

- if (reverseArc instanceof ToManyProperty) {
- for (Object relatedObject : relatedObjects) {
- ((ToManyProperty) reverseArc).removeTarget(
- relatedObject,
- object,
- true);
- }
+ // process remaining rules
+ switch (relationship.getDeleteRule()) {
+ case DeleteRule.NO_ACTION:
+ break;
+ case DeleteRule.NULLIFY:
+ ArcProperty reverseArc =
property.getComplimentaryReverseArc();
+
+ if (reverseArc == null) {
+ // nothing we can do here
+ break;
}
- else {
- for (Object relatedObject : relatedObjects) {
- ((ToOneProperty) reverseArc).setTarget(
- relatedObject,
- null,
- true);
- }
- }
- }

- break;
- case DeleteRule.CASCADE:
+ final Collection finalRelatedObjects = relatedObjects;

- Iterator<?> iterator = relatedObjects.iterator();
- while (iterator.hasNext()) {
- Persistent relatedObject = (Persistent)
iterator.next();
+ reverseArc.visit(new PropertyVisitor() {

- // this action object is stateless, so we can use
'performDelete'
- // recursively.
- performDelete(relatedObject);
- }
+ public boolean visitAttribute(AttributeProperty
property) {
+ return false;
+ }

- break;
- default:
- object.setPersistenceState(oldState);
- throw new CayenneRuntimeException("Invalid delete rule: "
+ deleteRule);
- }
- }
+ public boolean visitToMany(ToManyProperty
property) {
+ Iterator iterator =
finalRelatedObjects.iterator();
+ while (iterator.hasNext()) {
+ Object relatedObject = iterator.next();
+ property.removeTarget(relatedObject,
object, true);
+ }

- private Collection<?> relatedObjects(Object object, Property property)
{
- Object related = property.readProperty(object);
+ return false;
+ }

- if (related == null) {
- return Collections.EMPTY_LIST;
- }
- // return collections by copy, to allow removal of objects from
the underlying
- // relationship inside the iterator
- else if (property instanceof ToManyProperty) {
- Collection<?> relatedCollection = (Collection<?>) related;
- return relatedCollection.isEmpty()
- ? Collections.EMPTY_LIST
- : new ArrayList<Object>(relatedCollection);
- }
- // TODO: andrus 11/21/2007 - ToManyMapProperty check
- else {
- return Collections.singleton(related);
+ public boolean visitToOne(ToOneProperty property)
{
+ // Inverse is to-one - find all related
objects and
+ // nullify the reverse relationship
+ Iterator iterator =
finalRelatedObjects.iterator();
+ while (iterator.hasNext()) {
+ Object relatedObject = iterator.next();
+ property.setTarget(relatedObject, null,
true);
+ }
+ return false;
+ }
+ });
+
+ break;
+ case DeleteRule.CASCADE:
+ // Delete all related objects
+ Iterator iterator = relatedObjects.iterator();
+ while (iterator.hasNext()) {
+ Persistent relatedObject = (Persistent)
iterator.next();
+ performDelete(relatedObject);
+ }
+
+ break;
+ default:
+ object.setPersistenceState(oldState);
+ throw new CayenneRuntimeException("Invalid delete rule
"
+ + relationship.getDeleteRule());
+ }
}
}
}

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=881740&r1=881739&r2=881740&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
Wed Nov 18 12:08:20 2009
@@ -35,7 +35,6 @@
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataObject;
import org.apache.cayenne.DataRow;
-import org.apache.cayenne.DeleteDenyException;
import org.apache.cayenne.Fault;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.ObjectId;
@@ -54,7 +53,6 @@
import org.apache.cayenne.map.DbJoin;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.LifecycleEvent;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
@@ -629,18 +627,9 @@
// note that the order of initialization of persistence artifacts
below is
// important - do not change it lightly
object.setObjectId(id);
- object.setObjectContext(this);
- object.setPersistenceState(PersistenceState.NEW);
- getObjectStore().registerNode(id, object);
- getObjectStore().nodeCreated(id);

injectInitialValue(object);

- // invoke callbacks
- getEntityResolver().getCallbackRegistry().performCallbacks(
- LifecycleEvent.POST_ADD,
- object);
-
return object;
}

@@ -684,21 +673,17 @@
else {
persistent.setObjectId(new ObjectId(entity.getName()));
}
-
- persistent.setObjectContext(this);
- persistent.setPersistenceState(PersistenceState.NEW);
-
- getObjectStore().registerNode(persistent.getObjectId(), object);
- getObjectStore().nodeCreated(persistent.getObjectId());
-
- // now we need to find all arc changes, inject missing value
holders and pull in
- // all transient connected objects
-
+
ClassDescriptor descriptor =
getEntityResolver().getClassDescriptor(
entity.getName());
if (descriptor == null) {
throw new IllegalArgumentException("Invalid entity name: " +
entity.getName());
}
+
+ injectInitialValue(object);
+
+ // now we need to find all arc changes, inject missing value
holders and pull in
+ // all transient connected objects

descriptor.visitProperties(new PropertyVisitor() {

@@ -752,13 +737,6 @@
return true;
}
});
-
- injectInitialValue(object);
-
- // invoke callbacks
- getEntityResolver().getCallbackRegistry().performCallbacks(
- LifecycleEvent.POST_ADD,
- persistent);
}

/**
@@ -773,48 +751,6 @@
}

/**
- * 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.
- * relationships can be unset ("nullify" rule), deletion operation is
cascaded
- * (cascade rule).
- * <p>
- * <i>"Nullify" delete rule side effect: </i> passing a collection
representing
- * to-many relationship with nullify delete rule may result in objects
being removed
- * from collection.
- * </p>
- *
- * @since 1.2
- */
- public void deleteObjects(Collection objects) {
- if (objects.isEmpty()) {
- return;
- }
-
- // clone object list... this maybe a relationship collection with
nullify delete
- // rule, so modifying
- for (Persistent object : new ArrayList<Persistent>(objects)) {
- deleteObject(object);
- }
- }
-
- /**
- * Schedules an object 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. relationships
can be unset
- * ("nullify" rule), deletion operation is cascaded (cascade rule).
- *
- * @param object a persistent object that we want to delete.
- * @throws DeleteDenyException if a DENY delete rule is applicable for
object
- * deletion.
- * @throws NullPointerException if object is null.
- */
- @Override
- public void deleteObject(Object object) throws DeleteDenyException {
- new DataContextDeleteAction(this).performDelete((Persistent)
object);
- }
-
- /**
* If the parent channel is a DataContext, reverts local changes to
make this context
* look like the parent, if the parent channel is a DataDomain, reverts
all changes.
*

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
Wed Nov 18 12:08:20 2009
@@ -28,6 +28,7 @@

import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.DataChannelSyncCallbackAction;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.QueryResponse;
import org.apache.cayenne.access.jdbc.BatchQueryBuilderFactory;

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
Wed Nov 18 12:08:20 2009
@@ -99,6 +99,7 @@
*/
public void addListener(Class<?> entityClass, LifecycleListener
listener) {
addListener(LifecycleEvent.POST_ADD, entityClass, listener,
"postAdd");
+ addListener(LifecycleEvent.POST_PERSIST, entityClass, listener,
"prePersist");
addListener(LifecycleEvent.POST_PERSIST, entityClass, listener,
"postPersist");
addListener(LifecycleEvent.PRE_REMOVE, entityClass, listener,
"preRemove");
addListener(LifecycleEvent.POST_REMOVE, entityClass, listener,
"postRemove");

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
Wed Nov 18 12:08:20 2009
@@ -24,6 +24,7 @@

import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.DataChannelSyncCallbackAction;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
@@ -169,6 +170,14 @@
ObjectContext originatingContext,
GraphDiff changes,
int syncType) {
+
+ DataChannelSyncCallbackAction callbackAction =
DataChannelSyncCallbackAction
+ .getCallbackAction(
+ getEntityResolver().getCallbackRegistry(),
+ originatingContext.getGraphManager(),
+ changes,
+ syncType);
+ callbackAction.applyPreCommit();

changes = diffCompressor.compress(changes);

@@ -221,6 +230,7 @@
}
}

+ callbackAction.applyPostCommit();
return replyDiff;
}


Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java?rev=881740&view=auto

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
Wed Nov 18 12:08:20 2009
@@ -0,0 +1,114 @@
+/*****************************************************************
+ * 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.LifecycleListener;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.testdo.mt.ClientMtLifecycles;
+
+public class RemoteCallbacksTest extends RemoteCayenneCase implements
LifecycleListener {
+ private int added, loaded, prePersisted, postPersisted, preRemoved,
postRemoved, preUpdated, postUpdated;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ added = 0;
+ loaded = 0;
+ prePersisted = 0;
+ postPersisted = 0;
+ preRemoved = 0;
+ postRemoved = 0;
+ preUpdated = 0;
+ postUpdated = 0;
+ }
+
+ public void testDefault() throws InterruptedException {
+ ObjectContext context = createROPContext();
+
context.getEntityResolver().getCallbackRegistry().addListener(ClientMtLifecycles.class,
this);
+
+ assertAll(0, 0, 0, 0, 0, 0, 0, 0);
+ ClientMtLifecycles l1 =
context.newObject(ClientMtLifecycles.class);
+
+ assertAll(1, 0, 0, 0, 0, 0, 0, 0);
+ l1.setName("x");
+ assertAll(1, 0, 0, 0, 0, 0, 0, 0);
+
+ context.commitChanges();
+ Thread.sleep(5); //until commit
+ assertAll(1, 0, 1, 1, 0, 0, 0, 0);
+
+ l1.setName("x2");
+ assertAll(1, 0, 1, 1, 0, 0, 0, 0);
+
+ context.commitChanges();
+ Thread.sleep(5); //until commit
+ assertAll(1, 0, 1, 1, 1, 1, 0, 0);
+
+ context.deleteObject(l1);
+ assertAll(1, 0, 1, 1, 1, 1, 1, 0);
+
+ context.commitChanges();
+ Thread.sleep(5); //until commit
+ assertAll(1, 0, 1, 1, 1, 1, 1, 1);
+ }
+
+ private void assertAll(int added, int loaded, int prePersisted, int
postPersisted,
+ int preUpdated, int postUpdated, int preRemoved, int
postRemoved) {
+ assertEquals(this.added, added);
+ assertEquals(this.loaded, loaded);
+ assertEquals(this.prePersisted, prePersisted);
+ assertEquals(this.postPersisted, postPersisted);
+ assertEquals(this.preRemoved, preRemoved);
+ assertEquals(this.postRemoved, postRemoved);
+ assertEquals(this.preUpdated, preUpdated);
+ assertEquals(this.postUpdated, postUpdated);
+ }
+
+ public void postAdd(Object entity) {
+ added++;
+ }
+
+ public void postLoad(Object entity) {
+ loaded++;
+ }
+
+ public void postPersist(Object entity) {
+ postPersisted++;
+ }
+
+ public void postRemove(Object entity) {
+ postRemoved++;
+ }
+
+ public void postUpdate(Object entity) {
+ postUpdated++;
+ }
+
+ public void prePersist(Object entity) {
+ prePersisted++;
+ }
+
+ public void preRemove(Object entity) {
+ preRemoved++;
+ }
+
+ public void preUpdate(Object entity) {
+ preUpdated++;
+ }
+}

Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java?rev=881740&view=auto

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
Wed Nov 18 12:08:20 2009
@@ -0,0 +1,10 @@
+package org.apache.cayenne.testdo.mt;
+
+import org.apache.cayenne.testdo.mt.auto._ClientMtLifecycles;
+
+/**
+ * A persistent class mapped as "MtLifecycles" Cayenne entity.
+ */
+public class ClientMtLifecycles extends _ClientMtLifecycles {
+
+}

Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java?rev=881740&view=auto

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
Wed Nov 18 12:08:20 2009
@@ -0,0 +1,7 @@
+package org.apache.cayenne.testdo.mt;
+
+import org.apache.cayenne.testdo.mt.auto._MtLifecycles;
+
+public class MtLifecycles extends _MtLifecycles {
+
+}

Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java?rev=881740&view=auto

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
Wed Nov 18 12:08:20 2009
@@ -0,0 +1,37 @@
+package org.apache.cayenne.testdo.mt.auto;
+
+import org.apache.cayenne.PersistentObject;
+
+/**
+ * A generated persistent class mapped as "MtLifecycles" Cayenne entity.
It is a good idea to
+ * avoid changing this class manually, since it will be overwritten next
time code is
+ * regenerated. If you need to make any customizations, put them in a
subclass.
+ */
+public abstract class _ClientMtLifecycles extends PersistentObject {
+
+ public static final String NAME_PROPERTY = "name";
+
+ protected String name;
+
+ public String getName() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ }
+
+ return name;
+ }
+ public void setName(String name) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ }
+
+ Object oldValue = this.name;
+ this.name = name;
+
+ // notify objectContext about simple property change
+ if(objectContext != null) {
+ objectContext.propertyChanged(this, "name", oldValue, name);
+ }
+ }
+
+}

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
Wed Nov 18 12:08:20 2009
@@ -5,7 +5,7 @@
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.PersistentObject;
import org.apache.cayenne.query.NamedQuery;
-import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.MtTable1;

/**
* This class was generated by Cayenne.
@@ -15,15 +15,21 @@
*/
public class _ClientMultiTier {

- public List<ClientMtTable1> performAllMtTable1(ObjectContext context )
{
+ public static final String ALL_MT_TABLE1_QUERYNAME = "AllMtTable1";
+
+ public static final String MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
"MtQueryWithLocalCache";
+
+ public static final String
PARAMETERIZED_MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
"ParameterizedMtQueryWithLocalCache";
+
+ public List<MtTable1> performAllMtTable1(ObjectContext context ) {
return context.performQuery(new NamedQuery("AllMtTable1"));
}

- public List<ClientMtTable1> performMtQueryWithLocalCache(ObjectContext
context ) {
+ public List<MtTable1> performMtQueryWithLocalCache(ObjectContext
context ) {
return context.performQuery(new
NamedQuery("MtQueryWithLocalCache"));
}

- public List<ClientMtTable1>
performParameterizedMtQueryWithLocalCache(ObjectContext context , String g)
{
+ public List<MtTable1>
performParameterizedMtQueryWithLocalCache(ObjectContext context , String g)
{
String[] parameters = {
"g",
};

Added:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java?rev=881740&view=auto

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
Wed Nov 18 12:08:20 2009
@@ -0,0 +1,23 @@
+package org.apache.cayenne.testdo.mt.auto;
+
+import org.apache.cayenne.CayenneDataObject;
+
+/**
+ * Class _MtLifecycles was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _MtLifecycles extends CayenneDataObject {
+
+ public static final String NAME_PROPERTY = "name";
+
+
+ public void setName(String name) {
+ writeProperty("name", name);
+ }
+ public String getName() {
+ return (String)readProperty("name");
+ }
+
+}

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
Wed Nov 18 12:08:20 2009
@@ -14,6 +14,12 @@
*/
public class _MultiTier {

+ public static final String ALL_MT_TABLE1_QUERYNAME = "AllMtTable1";
+
+ public static final String MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
"MtQueryWithLocalCache";
+
+ public static final String
PARAMETERIZED_MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
"ParameterizedMtQueryWithLocalCache";
+
public List<MtTable1> performAllMtTable1(ObjectContext context ) {
return context.performQuery(new NamedQuery("AllMtTable1"));
}

Modified:
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml?rev=881740&r1=881739&r2=881740&view=diff

==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
Wed Nov 18 12:08:20 2009
@@ -29,6 +29,10 @@
<db-attribute name="TABLE4_ID" type="INTEGER"
isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="TABLE5_ID" type="INTEGER"
isPrimaryKey="true" isMandatory="true"/>
</db-entity>
+ <db-entity name="MT_LIFECYCLES">
+ <db-attribute name="ID" type="INTEGER" isPrimaryKey="true"
isMandatory="true"/>
+ <db-attribute name="NAME" type="VARCHAR" isMandatory="true"
length="100"/>
+ </db-entity>
<db-entity name="MT_MAP_TO_MANY">
<db-attribute name="ID" type="INTEGER" isPrimaryKey="true"
isMandatory="true"/>
</db-entity>
@@ -91,6 +95,9 @@
<obj-entity name="MtDeleteRule"
className="org.apache.cayenne.testdo.mt.MtDeleteRule"
clientClassName="org.apache.cayenne.testdo.mt.ClientMtDeleteRule"
dbEntityName="MT_DELETE_RULE">
<obj-attribute name="name" type="java.lang.String"
db-attribute-path="NAME"/>
</obj-entity>
+ <obj-entity name="MtLifecycles"
className="org.apache.cayenne.testdo.mt.MtLifecycles"
clientClassName="org.apache.cayenne.testdo.mt.ClientMtLifecycles"
dbEntityName="MT_LIFECYCLES">
+ <obj-attribute name="name" type="java.lang.String"
db-attribute-path="NAME"/>
+ </obj-entity>
<obj-entity name="MtMapToMany"
className="org.apache.cayenne.testdo.mt.MtMapToMany"
clientClassName="org.apache.cayenne.testdo.mt.ClientMtMapToMany"
dbEntityName="MT_MAP_TO_MANY">
</obj-entity>
<obj-entity name="MtMapToManyTarget"
className="org.apache.cayenne.testdo.mt.MtMapToManyTarget"
clientClassName="org.apache.cayenne.testdo.mt.ClientMtMapToManyTarget"
dbEntityName="MT_MAP_TO_MANY_TARGET">


--
Olga Tkacheva

Search Discussions

  • Andrey Razumovsky at Nov 18, 2009 at 6:58 pm
    Sorry for that. Missed to check that module.
    Actually what caused the error is breakage in code generation. Need to check
    it first..

    2009/11/18 Ольга Ткачева <tkachovaolga@gmail.com>
    Andrey, after your commit I have this problem:

    [INFO] Compilation failure

    /home/olga/cayenne-git/framework/cayenne-tools/src/test/java/org/apache/cayenne/gen/ClientDataMapGeneratedQueryRunTest.java:[59,86]
    incompatible types
    found : java.util.List<org.apache.cayenne.testdo.mt.MtTable1>
    required: java.util.List<org.apache.cayenne.testdo.mt.ClientMtTable1>

    and reasonable error in cayenne-tools.


    2009/11/18 <andrey@apache.org>
    Author: andrey
    Date: Wed Nov 18 12:08:20 2009
    New Revision: 881740

    URL: http://svn.apache.org/viewvc?rev=881740&view=rev
    Log:
    CAY-1312 Allow lifecycle callbacks on ROP client. Only method invokes, i.e.
    no configuration for those callbacks yet

    Added:

    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
    - copied, changed from r881253,
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
    Removed:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.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/ObjectContextDeleteAction.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/main/java/org/apache/cayenne/access/DataDomain.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
    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=881740&r1=881739&r2=881740&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
    Wed Nov 18 12:08:20 2009
    @@ -33,6 +33,7 @@
    import org.apache.cayenne.graph.GraphEvent;
    import org.apache.cayenne.graph.GraphManager;
    import org.apache.cayenne.map.EntityResolver;
    +import org.apache.cayenne.map.LifecycleEvent;
    import org.apache.cayenne.map.ObjEntity;
    import org.apache.cayenne.query.ObjectIdQuery;
    import org.apache.cayenne.query.Query;
    @@ -103,8 +104,6 @@

    public abstract void commitChangesToParent();

    - public abstract void deleteObject(Object object) throws
    DeleteDenyException;
    -
    public abstract Collection<?> deletedObjects();

    public DataChannel getChannel() {
    @@ -381,9 +380,24 @@
    }

    /**
    - * If ObjEntity qualifier is set, asks it to inject initial value to
    an object
    + * If ObjEntity qualifier is set, asks it to inject initial value to
    an object.
    + * Also performs all Persistent initialization operations
    */
    - protected void injectInitialValue(Object object) {
    + protected void injectInitialValue(Object obj) {
    + // 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
    +
    + Persistent object = (Persistent) obj;
    +
    + object.setObjectContext(this);
    + object.setPersistenceState(PersistenceState.NEW);
    +
    + GraphManager graphManager = getGraphManager();
    + synchronized (graphManager) {
    + graphManager.registerNode(object.getObjectId(), object);
    + graphManager.nodeCreated(object.getObjectId());
    + }
    +
    ObjEntity entity;
    try {
    entity =
    getEntityResolver().lookupObjEntity(object.getClass());
    @@ -398,5 +412,37 @@
    ((ValueInjector)
    entity.getDeclaredQualifier()).injectValue(object);
    }
    }
    +
    + // invoke callbacks
    + getEntityResolver().getCallbackRegistry().performCallbacks(
    + LifecycleEvent.POST_ADD,
    + object);
    + }
    +
    + /**
    + * Schedules an object for deletion on the next commit of this
    context. Object's
    + * persistence state is changed to PersistenceState.DELETED; objects
    related to this
    + * object are processed according to delete rules, i.e.
    relationships
    can be unset
    + * ("nullify" rule), deletion operation is cascaded (cascade rule).
    + *
    + * @param object a persistent object that we want to delete.
    + * @throws DeleteDenyException if a DENY delete rule is applicable for
    object
    + * deletion.
    + * @throws NullPointerException if object is null.
    + */
    + public void deleteObject(Object object) {
    + new ObjectContextDeleteAction(this).performDelete((Persistent)
    object);
    + }
    +
    + public void deleteObjects(Collection<?> objects) throws
    DeleteDenyException {
    + if (objects.isEmpty())
    + return;
    +
    + // Don't call deleteObject() directly since it would be less
    efficient.
    + ObjectContextDeleteAction ocda = new
    ObjectContextDeleteAction(this);
    +
    + // Make a copy to iterate over to avoid
    ConcurrentModificationException.
    + for (Persistent object : (ArrayList<Persistent>) new
    ArrayList(objects))
    + ocda.performDelete(object);
    }
    }
    \ 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=881740&r1=881739&r2=881740&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
    Wed Nov 18 12:08:20 2009
    @@ -308,27 +308,6 @@
    }

    /**
    - * Deletes an object locally, scheduling it for future deletion from
    the external data
    - * store.
    - */
    - @Override
    - public void deleteObject(Object object) {
    - new ObjectContextDeleteAction(this).performDelete((Persistent)
    object);
    - }
    -
    - public void deleteObjects(Collection<?> objects) throws
    DeleteDenyException {
    - if (objects.isEmpty())
    - return;
    -
    - // Don't call deleteObject() directly since it would be less
    efficient.
    - ObjectContextDeleteAction ocda = new
    ObjectContextDeleteAction(this);
    -
    - // Make a copy to iterate over to avoid
    ConcurrentModificationException.
    - for (Persistent object : (ArrayList<Persistent>) new
    ArrayList(objects))
    - ocda.performDelete(object);
    - }
    -
    - /**
    * Creates and registers a new Persistent object instance.
    */
    @Override
    @@ -527,16 +506,6 @@
    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.setObjectContext(this);
    - object.setPersistenceState(PersistenceState.NEW);
    -
    - synchronized (graphManager) {
    - graphManager.registerNode(id, object);
    - graphManager.nodeCreated(id);
    - }
    -
    injectInitialValue(object);
    }


    Copied:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
    (from r881253,
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java)
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java?p2=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java&p1=cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java&r1=881253&r2=881740&rev=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataChannelSyncCallbackAction.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncCallbackAction.java
    Wed Nov 18 12:08:20 2009
    @@ -16,14 +16,13 @@
    * specific language governing permissions and limitations
    * under the License.
    ****************************************************************/
    -package org.apache.cayenne.access;
    +package org.apache.cayenne;

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Set;

    -import org.apache.cayenne.DataChannel;
    import org.apache.cayenne.graph.GraphChangeHandler;
    import org.apache.cayenne.graph.GraphDiff;
    import org.apache.cayenne.graph.GraphManager;
    @@ -32,10 +31,11 @@

    /**
    * @since 3.0
    + * note: made public in 3.1 to be used in all tiers
    */
    -abstract class DataChannelSyncCallbackAction implements
    GraphChangeHandler
    {
    +public abstract class DataChannelSyncCallbackAction implements
    GraphChangeHandler {

    - static DataChannelSyncCallbackAction getCallbackAction(
    + public static DataChannelSyncCallbackAction getCallbackAction(
    LifecycleCallbackRegistry callbackRegistry,
    GraphManager graphManager,
    GraphDiff changes,
    @@ -73,9 +73,9 @@

    protected abstract boolean hasListeners();

    - abstract void applyPreCommit();
    + public abstract void applyPreCommit();

    - abstract void applyPostCommit();
    + public abstract void applyPostCommit();

    void apply(LifecycleEvent callbackType, Collection<?> objects) {
    if (seenIds != null && objects != null) {
    @@ -166,13 +166,13 @@
    }

    @Override
    - void applyPreCommit() {
    + public void applyPreCommit() {
    apply(LifecycleEvent.PRE_PERSIST, persisted);
    apply(LifecycleEvent.PRE_UPDATE, updated);
    }

    @Override
    - void applyPostCommit() {
    + public void applyPostCommit() {
    apply(LifecycleEvent.POST_UPDATE, updated);
    apply(LifecycleEvent.POST_REMOVE, removed);
    apply(LifecycleEvent.POST_PERSIST, persisted);
    @@ -192,12 +192,12 @@
    }

    @Override
    - void applyPreCommit() {
    + public void applyPreCommit() {
    // noop
    }

    @Override
    - void applyPostCommit() {
    + public void applyPostCommit() {
    apply(LifecycleEvent.POST_LOAD, updated);
    apply(LifecycleEvent.POST_LOAD, removed);
    }

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/ObjectContextDeleteAction.java
    Wed Nov 18 12:08:20 2009
    @@ -23,14 +23,14 @@
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Iterator;
    +import java.util.Map;

    import org.apache.cayenne.map.DeleteRule;
    -import org.apache.cayenne.map.ObjEntity;
    +import org.apache.cayenne.map.LifecycleEvent;
    import org.apache.cayenne.map.ObjRelationship;
    import org.apache.cayenne.reflect.ArcProperty;
    import org.apache.cayenne.reflect.AttributeProperty;
    import org.apache.cayenne.reflect.ClassDescriptor;
    -import org.apache.cayenne.reflect.Property;
    import org.apache.cayenne.reflect.PropertyVisitor;
    import org.apache.cayenne.reflect.ToManyProperty;
    import org.apache.cayenne.reflect.ToOneProperty;
    @@ -54,6 +54,10 @@

    if (oldState == PersistenceState.TRANSIENT
    oldState == PersistenceState.DELETED) {
    + // Drop out... especially in case of DELETED we might be about
    to get
    + // into a horrible recursive loop due to CASCADE delete rules.
    + // Assume that everything must have been done correctly
    already
    + // and *don't* do it again
    return false;
    }

    @@ -69,6 +73,11 @@
    + ", context: "
    + context);
    }
    +
    + // must resolve HOLLOW objects before delete... needed
    + // to process relationships and optimistic locking...
    +
    + context.prepareForAccess(object, null, false);

    if (oldState == PersistenceState.NEW) {
    deleteNew(object);
    @@ -80,133 +89,148 @@
    return true;
    }

    - private void deleteNew(Persistent object) {
    + private void deleteNew(Persistent object) throws DeleteDenyException {
    object.setPersistenceState(PersistenceState.TRANSIENT);
    processDeleteRules(object, PersistenceState.NEW);
    +
    + // if an object was NEW, we must throw it out
    context.getGraphManager().unregisterNode(object.getObjectId());
    }

    - private void deletePersistent(Persistent object) {
    + private void deletePersistent(Persistent object) throws
    DeleteDenyException {
    +
    context.getEntityResolver().getCallbackRegistry().performCallbacks(
    + LifecycleEvent.PRE_REMOVE,
    + object);
    +
    int oldState = object.getPersistenceState();
    object.setPersistenceState(PersistenceState.DELETED);
    processDeleteRules(object, oldState);
    context.getGraphManager().nodeRemoved(object.getObjectId());
    }

    - private void processDeleteRules(final Persistent object, final int
    oldState) {
    + private Collection toCollection(Object object) {

    - String entityName = object.getObjectId().getEntityName();
    - final ObjEntity entity =
    context.getEntityResolver().getObjEntity(entityName);
    - ClassDescriptor descriptor =
    context.getEntityResolver().getClassDescriptor(
    - entityName);
    + if (object == null) {
    + return Collections.EMPTY_LIST;
    + }

    - descriptor.visitProperties(new PropertyVisitor() {
    + // create copies of collections to avoid iterator exceptions
    + if (object instanceof Collection) {
    + return new ArrayList((Collection) object);
    + }
    + else if (object instanceof Map) {
    + return new ArrayList(((Map) object).values());
    + }
    + else {
    + return Collections.singleton(object);
    + }
    + }

    - public boolean visitToMany(ToManyProperty property) {
    - ObjRelationship relationship = (ObjRelationship) entity
    - .getRelationship(property.getName());
    + private void processDeleteRules(final Persistent object, int oldState)
    + throws DeleteDenyException {

    - processRules(object, property,
    relationship.getDeleteRule(), oldState);
    - return true;
    - }
    + ClassDescriptor descriptor =
    context.getEntityResolver().getClassDescriptor(
    + object.getObjectId().getEntityName());

    - public boolean visitToOne(ToOneProperty property) {
    - ObjRelationship relationship = (ObjRelationship) entity
    - .getRelationship(property.getName());
    + for (final ObjRelationship relationship :
    descriptor.getEntity().getRelationships()) {

    - processRules(object, property,
    relationship.getDeleteRule(), oldState);
    - return true;
    - }
    + boolean processFlattened = relationship.isFlattened()
    + && relationship.isToDependentEntity()
    + && !relationship.isReadOnly();

    - public boolean visitAttribute(AttributeProperty property) {
    - return true;
    + // first check for no action... bail out if no flattened
    processing is needed
    + if (relationship.getDeleteRule() == DeleteRule.NO_ACTION &&
    !processFlattened) {
    + continue;
    }
    - });
    - }
    -
    - private void processRules(
    - Persistent object,
    - ArcProperty property,
    - int deleteRule,
    - int oldState) {
    -
    - if (deleteRule == DeleteRule.NO_ACTION) {
    - return;
    - }
    -
    - Collection<?> relatedObjects = relatedObjects(object, property);
    - if (relatedObjects.isEmpty()) {
    - return;
    - }

    - switch (deleteRule) {
    + ArcProperty property = (ArcProperty)
    descriptor.getProperty(relationship
    + .getName());
    + Collection relatedObjects =
    toCollection(property.readProperty(object));
    +
    + // no related object, bail out
    + if (relatedObjects.size() == 0) {
    + continue;
    + }

    - case DeleteRule.DENY:
    + // process DENY rule first...
    + if (relationship.getDeleteRule() == DeleteRule.DENY) {
    object.setPersistenceState(oldState);
    +
    String message = relatedObjects.size() == 1
    ? "1 related object"
    : relatedObjects.size() + " related objects";
    - throw new DeleteDenyException(object,
    property.getName(),
    message);
    -
    - case DeleteRule.NULLIFY:
    - ArcProperty reverseArc =
    property.getComplimentaryReverseArc();
    + throw new DeleteDenyException(object,
    relationship.getName(), message);
    + }

    - if (reverseArc != null) {
    + // process flattened with dependent join tables...
    + // joins must be removed even if they are non-existent or
    ignored in the
    + // object graph
    + if (processFlattened) {
    + Iterator iterator = relatedObjects.iterator();
    + while (iterator.hasNext()) {
    + Persistent relatedObject = (Persistent)
    iterator.next();
    +
    context.getGraphManager().arcDeleted(object.getObjectId(), relatedObject
    + .getObjectId(), relationship.getName());
    + }
    + }

    - if (reverseArc instanceof ToManyProperty) {
    - for (Object relatedObject : relatedObjects) {
    - ((ToManyProperty) reverseArc).removeTarget(
    - relatedObject,
    - object,
    - true);
    - }
    + // process remaining rules
    + switch (relationship.getDeleteRule()) {
    + case DeleteRule.NO_ACTION:
    + break;
    + case DeleteRule.NULLIFY:
    + ArcProperty reverseArc =
    property.getComplimentaryReverseArc();
    +
    + if (reverseArc == null) {
    + // nothing we can do here
    + break;
    }
    - else {
    - for (Object relatedObject : relatedObjects) {
    - ((ToOneProperty) reverseArc).setTarget(
    - relatedObject,
    - null,
    - true);
    - }
    - }
    - }

    - break;
    - case DeleteRule.CASCADE:
    + final Collection finalRelatedObjects =
    relatedObjects;
    - Iterator<?> iterator = relatedObjects.iterator();
    - while (iterator.hasNext()) {
    - Persistent relatedObject = (Persistent)
    iterator.next();
    + reverseArc.visit(new PropertyVisitor() {

    - // this action object is stateless, so we can use
    'performDelete'
    - // recursively.
    - performDelete(relatedObject);
    - }
    + public boolean visitAttribute(AttributeProperty
    property) {
    + return false;
    + }

    - break;
    - default:
    - object.setPersistenceState(oldState);
    - throw new CayenneRuntimeException("Invalid delete rule: "
    + deleteRule);
    - }
    - }
    + public boolean visitToMany(ToManyProperty
    property) {
    + Iterator iterator =
    finalRelatedObjects.iterator();
    + while (iterator.hasNext()) {
    + Object relatedObject = iterator.next();
    + property.removeTarget(relatedObject,
    object, true);
    + }

    - private Collection<?> relatedObjects(Object object, Property property)
    {
    - Object related = property.readProperty(object);
    + return false;
    + }

    - if (related == null) {
    - return Collections.EMPTY_LIST;
    - }
    - // return collections by copy, to allow removal of objects from
    the underlying
    - // relationship inside the iterator
    - else if (property instanceof ToManyProperty) {
    - Collection<?> relatedCollection = (Collection<?>) related;
    - return relatedCollection.isEmpty()
    - ? Collections.EMPTY_LIST
    - : new ArrayList<Object>(relatedCollection);
    - }
    - // TODO: andrus 11/21/2007 - ToManyMapProperty check
    - else {
    - return Collections.singleton(related);
    + public boolean visitToOne(ToOneProperty property)
    {
    + // Inverse is to-one - find all related
    objects and
    + // nullify the reverse relationship
    + Iterator iterator =
    finalRelatedObjects.iterator();
    + while (iterator.hasNext()) {
    + Object relatedObject = iterator.next();
    + property.setTarget(relatedObject, null,
    true);
    + }
    + return false;
    + }
    + });
    +
    + break;
    + case DeleteRule.CASCADE:
    + // Delete all related objects
    + Iterator iterator = relatedObjects.iterator();
    + while (iterator.hasNext()) {
    + Persistent relatedObject = (Persistent)
    iterator.next();
    + performDelete(relatedObject);
    + }
    +
    + break;
    + default:
    + object.setPersistenceState(oldState);
    + throw new CayenneRuntimeException("Invalid delete rule
    "
    + + relationship.getDeleteRule());
    + }
    }
    }
    }

    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=881740&r1=881739&r2=881740&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
    Wed Nov 18 12:08:20 2009
    @@ -35,7 +35,6 @@
    import org.apache.cayenne.DataChannel;
    import org.apache.cayenne.DataObject;
    import org.apache.cayenne.DataRow;
    -import org.apache.cayenne.DeleteDenyException;
    import org.apache.cayenne.Fault;
    import org.apache.cayenne.ObjectContext;
    import org.apache.cayenne.ObjectId;
    @@ -54,7 +53,6 @@
    import org.apache.cayenne.map.DbJoin;
    import org.apache.cayenne.map.DbRelationship;
    import org.apache.cayenne.map.EntityResolver;
    -import org.apache.cayenne.map.LifecycleEvent;
    import org.apache.cayenne.map.ObjAttribute;
    import org.apache.cayenne.map.ObjEntity;
    import org.apache.cayenne.map.ObjRelationship;
    @@ -629,18 +627,9 @@
    // note that the order of initialization of persistence artifacts
    below is
    // important - do not change it lightly
    object.setObjectId(id);
    - object.setObjectContext(this);
    - object.setPersistenceState(PersistenceState.NEW);
    - getObjectStore().registerNode(id, object);
    - getObjectStore().nodeCreated(id);

    injectInitialValue(object);

    - // invoke callbacks
    - getEntityResolver().getCallbackRegistry().performCallbacks(
    - LifecycleEvent.POST_ADD,
    - object);
    -
    return object;
    }

    @@ -684,21 +673,17 @@
    else {
    persistent.setObjectId(new ObjectId(entity.getName()));
    }
    -
    - persistent.setObjectContext(this);
    - persistent.setPersistenceState(PersistenceState.NEW);
    -
    - getObjectStore().registerNode(persistent.getObjectId(), object);
    - getObjectStore().nodeCreated(persistent.getObjectId());
    -
    - // now we need to find all arc changes, inject missing value
    holders and pull in
    - // all transient connected objects
    -
    +
    ClassDescriptor descriptor =
    getEntityResolver().getClassDescriptor(
    entity.getName());
    if (descriptor == null) {
    throw new IllegalArgumentException("Invalid entity name: " +
    entity.getName());
    }
    +
    + injectInitialValue(object);
    +
    + // now we need to find all arc changes, inject missing value
    holders and pull in
    + // all transient connected objects

    descriptor.visitProperties(new PropertyVisitor() {

    @@ -752,13 +737,6 @@
    return true;
    }
    });
    -
    - injectInitialValue(object);
    -
    - // invoke callbacks
    - getEntityResolver().getCallbackRegistry().performCallbacks(
    - LifecycleEvent.POST_ADD,
    - persistent);
    }

    /**
    @@ -773,48 +751,6 @@
    }

    /**
    - * 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.
    - * relationships can be unset ("nullify" rule), deletion operation is
    cascaded
    - * (cascade rule).
    - * <p>
    - * <i>"Nullify" delete rule side effect: </i> passing a collection
    representing
    - * to-many relationship with nullify delete rule may result in objects
    being removed
    - * from collection.
    - * </p>
    - *
    - * @since 1.2
    - */
    - public void deleteObjects(Collection objects) {
    - if (objects.isEmpty()) {
    - return;
    - }
    -
    - // clone object list... this maybe a relationship collection with
    nullify delete
    - // rule, so modifying
    - for (Persistent object : new ArrayList<Persistent>(objects)) {
    - deleteObject(object);
    - }
    - }
    -
    - /**
    - * Schedules an object 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.
    relationships
    can be unset
    - * ("nullify" rule), deletion operation is cascaded (cascade rule).
    - *
    - * @param object a persistent object that we want to delete.
    - * @throws DeleteDenyException if a DENY delete rule is applicable for
    object
    - * deletion.
    - * @throws NullPointerException if object is null.
    - */
    - @Override
    - public void deleteObject(Object object) throws DeleteDenyException {
    - new DataContextDeleteAction(this).performDelete((Persistent)
    object);
    - }
    -
    - /**
    * If the parent channel is a DataContext, reverts local changes to
    make this context
    * look like the parent, if the parent channel is a DataDomain, reverts
    all changes.
    *

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomain.java
    Wed Nov 18 12:08:20 2009
    @@ -28,6 +28,7 @@

    import org.apache.cayenne.CayenneRuntimeException;
    import org.apache.cayenne.DataChannel;
    +import org.apache.cayenne.DataChannelSyncCallbackAction;
    import org.apache.cayenne.ObjectContext;
    import org.apache.cayenne.QueryResponse;
    import org.apache.cayenne.access.jdbc.BatchQueryBuilderFactory;

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackRegistry.java
    Wed Nov 18 12:08:20 2009
    @@ -99,6 +99,7 @@
    */
    public void addListener(Class<?> entityClass, LifecycleListener
    listener) {
    addListener(LifecycleEvent.POST_ADD, entityClass, listener,
    "postAdd");
    + addListener(LifecycleEvent.POST_PERSIST, entityClass, listener,
    "prePersist");
    addListener(LifecycleEvent.POST_PERSIST, entityClass, listener,
    "postPersist");
    addListener(LifecycleEvent.PRE_REMOVE, entityClass, listener,
    "preRemove");
    addListener(LifecycleEvent.POST_REMOVE, entityClass, listener,
    "postRemove");

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/remote/ClientChannel.java
    Wed Nov 18 12:08:20 2009
    @@ -24,6 +24,7 @@

    import org.apache.cayenne.CayenneRuntimeException;
    import org.apache.cayenne.DataChannel;
    +import org.apache.cayenne.DataChannelSyncCallbackAction;
    import org.apache.cayenne.ObjectContext;
    import org.apache.cayenne.ObjectId;
    import org.apache.cayenne.Persistent;
    @@ -169,6 +170,14 @@
    ObjectContext originatingContext,
    GraphDiff changes,
    int syncType) {
    +
    + DataChannelSyncCallbackAction callbackAction =
    DataChannelSyncCallbackAction
    + .getCallbackAction(
    + getEntityResolver().getCallbackRegistry(),
    + originatingContext.getGraphManager(),
    + changes,
    + syncType);
    + callbackAction.applyPreCommit();

    changes = diffCompressor.compress(changes);

    @@ -221,6 +230,7 @@
    }
    }

    + callbackAction.applyPostCommit();
    return replyDiff;
    }


    Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java?rev=881740&view=auto
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
    (added)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/remote/RemoteCallbacksTest.java
    Wed Nov 18 12:08:20 2009
    @@ -0,0 +1,114 @@
    +/*****************************************************************
    + * 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.LifecycleListener;
    +import org.apache.cayenne.ObjectContext;
    +import org.apache.cayenne.testdo.mt.ClientMtLifecycles;
    +
    +public class RemoteCallbacksTest extends RemoteCayenneCase implements
    LifecycleListener {
    + private int added, loaded, prePersisted, postPersisted, preRemoved,
    postRemoved, preUpdated, postUpdated;
    +
    + @Override
    + public void setUp() throws Exception {
    + super.setUp();
    + added = 0;
    + loaded = 0;
    + prePersisted = 0;
    + postPersisted = 0;
    + preRemoved = 0;
    + postRemoved = 0;
    + preUpdated = 0;
    + postUpdated = 0;
    + }
    +
    + public void testDefault() throws InterruptedException {
    + ObjectContext context = createROPContext();
    +
    context.getEntityResolver().getCallbackRegistry().addListener(ClientMtLifecycles.class,
    this);
    +
    + assertAll(0, 0, 0, 0, 0, 0, 0, 0);
    + ClientMtLifecycles l1 =
    context.newObject(ClientMtLifecycles.class);
    +
    + assertAll(1, 0, 0, 0, 0, 0, 0, 0);
    + l1.setName("x");
    + assertAll(1, 0, 0, 0, 0, 0, 0, 0);
    +
    + context.commitChanges();
    + Thread.sleep(5); //until commit
    + assertAll(1, 0, 1, 1, 0, 0, 0, 0);
    +
    + l1.setName("x2");
    + assertAll(1, 0, 1, 1, 0, 0, 0, 0);
    +
    + context.commitChanges();
    + Thread.sleep(5); //until commit
    + assertAll(1, 0, 1, 1, 1, 1, 0, 0);
    +
    + context.deleteObject(l1);
    + assertAll(1, 0, 1, 1, 1, 1, 1, 0);
    +
    + context.commitChanges();
    + Thread.sleep(5); //until commit
    + assertAll(1, 0, 1, 1, 1, 1, 1, 1);
    + }
    +
    + private void assertAll(int added, int loaded, int prePersisted, int
    postPersisted,
    + int preUpdated, int postUpdated, int preRemoved, int
    postRemoved) {
    + assertEquals(this.added, added);
    + assertEquals(this.loaded, loaded);
    + assertEquals(this.prePersisted, prePersisted);
    + assertEquals(this.postPersisted, postPersisted);
    + assertEquals(this.preRemoved, preRemoved);
    + assertEquals(this.postRemoved, postRemoved);
    + assertEquals(this.preUpdated, preUpdated);
    + assertEquals(this.postUpdated, postUpdated);
    + }
    +
    + public void postAdd(Object entity) {
    + added++;
    + }
    +
    + public void postLoad(Object entity) {
    + loaded++;
    + }
    +
    + public void postPersist(Object entity) {
    + postPersisted++;
    + }
    +
    + public void postRemove(Object entity) {
    + postRemoved++;
    + }
    +
    + public void postUpdate(Object entity) {
    + postUpdated++;
    + }
    +
    + public void prePersist(Object entity) {
    + prePersisted++;
    + }
    +
    + public void preRemove(Object entity) {
    + preRemoved++;
    + }
    +
    + public void preUpdate(Object entity) {
    + preUpdated++;
    + }
    +}

    Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java?rev=881740&view=auto
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
    (added)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/ClientMtLifecycles.java
    Wed Nov 18 12:08:20 2009
    @@ -0,0 +1,10 @@
    +package org.apache.cayenne.testdo.mt;
    +
    +import org.apache.cayenne.testdo.mt.auto._ClientMtLifecycles;
    +
    +/**
    + * A persistent class mapped as "MtLifecycles" Cayenne entity.
    + */
    +public class ClientMtLifecycles extends _ClientMtLifecycles {
    +
    +}

    Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java?rev=881740&view=auto
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
    (added)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/MtLifecycles.java
    Wed Nov 18 12:08:20 2009
    @@ -0,0 +1,7 @@
    +package org.apache.cayenne.testdo.mt;
    +
    +import org.apache.cayenne.testdo.mt.auto._MtLifecycles;
    +
    +public class MtLifecycles extends _MtLifecycles {
    +
    +}

    Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java?rev=881740&view=auto
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
    (added)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtLifecycles.java
    Wed Nov 18 12:08:20 2009
    @@ -0,0 +1,37 @@
    +package org.apache.cayenne.testdo.mt.auto;
    +
    +import org.apache.cayenne.PersistentObject;
    +
    +/**
    + * A generated persistent class mapped as "MtLifecycles" Cayenne entity.
    It is a good idea to
    + * avoid changing this class manually, since it will be overwritten next
    time code is
    + * regenerated. If you need to make any customizations, put them in a
    subclass.
    + */
    +public abstract class _ClientMtLifecycles extends PersistentObject {
    +
    + public static final String NAME_PROPERTY = "name";
    +
    + protected String name;
    +
    + public String getName() {
    + if(objectContext != null) {
    + objectContext.prepareForAccess(this, "name", false);
    + }
    +
    + return name;
    + }
    + public void setName(String name) {
    + if(objectContext != null) {
    + objectContext.prepareForAccess(this, "name", false);
    + }
    +
    + Object oldValue = this.name;
    + this.name = name;
    +
    + // notify objectContext about simple property change
    + if(objectContext != null) {
    + objectContext.propertyChanged(this, "name", oldValue, name);
    + }
    + }
    +
    +}

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMultiTier.java
    Wed Nov 18 12:08:20 2009
    @@ -5,7 +5,7 @@
    import org.apache.cayenne.ObjectContext;
    import org.apache.cayenne.PersistentObject;
    import org.apache.cayenne.query.NamedQuery;
    -import org.apache.cayenne.testdo.mt.ClientMtTable1;
    +import org.apache.cayenne.testdo.mt.MtTable1;

    /**
    * This class was generated by Cayenne.
    @@ -15,15 +15,21 @@
    */
    public class _ClientMultiTier {

    - public List<ClientMtTable1> performAllMtTable1(ObjectContext context )
    {
    + public static final String ALL_MT_TABLE1_QUERYNAME = "AllMtTable1";
    +
    + public static final String MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
    "MtQueryWithLocalCache";
    +
    + public static final String
    PARAMETERIZED_MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
    "ParameterizedMtQueryWithLocalCache";
    +
    + public List<MtTable1> performAllMtTable1(ObjectContext context ) {
    return context.performQuery(new NamedQuery("AllMtTable1"));
    }

    - public List<ClientMtTable1>
    performMtQueryWithLocalCache(ObjectContext
    context ) {
    + public List<MtTable1> performMtQueryWithLocalCache(ObjectContext
    context ) {
    return context.performQuery(new
    NamedQuery("MtQueryWithLocalCache"));
    }

    - public List<ClientMtTable1>
    performParameterizedMtQueryWithLocalCache(ObjectContext context , String g)
    {
    + public List<MtTable1>
    performParameterizedMtQueryWithLocalCache(ObjectContext context , String g)
    {
    String[] parameters = {
    "g",
    };

    Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java?rev=881740&view=auto
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
    (added)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MtLifecycles.java
    Wed Nov 18 12:08:20 2009
    @@ -0,0 +1,23 @@
    +package org.apache.cayenne.testdo.mt.auto;
    +
    +import org.apache.cayenne.CayenneDataObject;
    +
    +/**
    + * Class _MtLifecycles was generated by Cayenne.
    + * It is probably a good idea to avoid changing this class manually,
    + * since it may be overwritten next time code is regenerated.
    + * If you need to make any customizations, please use subclass.
    + */
    +public abstract class _MtLifecycles extends CayenneDataObject {
    +
    + public static final String NAME_PROPERTY = "name";
    +
    +
    + public void setName(String name) {
    + writeProperty("name", name);
    + }
    + public String getName() {
    + return (String)readProperty("name");
    + }
    +
    +}

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/mt/auto/_MultiTier.java
    Wed Nov 18 12:08:20 2009
    @@ -14,6 +14,12 @@
    */
    public class _MultiTier {

    + public static final String ALL_MT_TABLE1_QUERYNAME = "AllMtTable1";
    +
    + public static final String MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
    "MtQueryWithLocalCache";
    +
    + public static final String
    PARAMETERIZED_MT_QUERY_WITH_LOCAL_CACHE_QUERYNAME =
    "ParameterizedMtQueryWithLocalCache";
    +
    public List<MtTable1> performAllMtTable1(ObjectContext context ) {
    return context.performQuery(new NamedQuery("AllMtTable1"));
    }

    Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
    URL:
    http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml?rev=881740&r1=881739&r2=881740&view=diff
    ==============================================================================
    ---
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
    (original)
    +++
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/multi-tier.map.xml
    Wed Nov 18 12:08:20 2009
    @@ -29,6 +29,10 @@
    <db-attribute name="TABLE4_ID" type="INTEGER"
    isPrimaryKey="true" isMandatory="true"/>
    <db-attribute name="TABLE5_ID" type="INTEGER"
    isPrimaryKey="true" isMandatory="true"/>
    </db-entity>
    + <db-entity name="MT_LIFECYCLES">
    + <db-attribute name="ID" type="INTEGER"
    isPrimaryKey="true"
    isMandatory="true"/>
    + <db-attribute name="NAME" type="VARCHAR"
    isMandatory="true"
    length="100"/>
    + </db-entity>
    <db-entity name="MT_MAP_TO_MANY">
    <db-attribute name="ID" type="INTEGER" isPrimaryKey="true"
    isMandatory="true"/>
    </db-entity>
    @@ -91,6 +95,9 @@
    <obj-entity name="MtDeleteRule"
    className="org.apache.cayenne.testdo.mt.MtDeleteRule"
    clientClassName="org.apache.cayenne.testdo.mt.ClientMtDeleteRule"
    dbEntityName="MT_DELETE_RULE">
    <obj-attribute name="name" type="java.lang.String"
    db-attribute-path="NAME"/>
    </obj-entity>
    + <obj-entity name="MtLifecycles"
    className="org.apache.cayenne.testdo.mt.MtLifecycles"
    clientClassName="org.apache.cayenne.testdo.mt.ClientMtLifecycles"
    dbEntityName="MT_LIFECYCLES">
    + <obj-attribute name="name" type="java.lang.String"
    db-attribute-path="NAME"/>
    + </obj-entity>
    <obj-entity name="MtMapToMany"
    className="org.apache.cayenne.testdo.mt.MtMapToMany"
    clientClassName="org.apache.cayenne.testdo.mt.ClientMtMapToMany"
    dbEntityName="MT_MAP_TO_MANY">
    </obj-entity>
    <obj-entity name="MtMapToManyTarget"
    className="org.apache.cayenne.testdo.mt.MtMapToManyTarget"
    clientClassName="org.apache.cayenne.testdo.mt.ClientMtMapToManyTarget"
    dbEntityName="MT_MAP_TO_MANY_TARGET">


    --
    Olga Tkacheva


    --
    Andrey

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupdev @
categoriescayenne
postedNov 18, '09 at 2:29p
activeNov 18, '09 at 6:58p
posts2
users2
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase