You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/07/20 04:33:26 UTC

svn commit: r423717 - in /incubator/cayenne/main/trunk/cayenne/cayenne-java/src: cayenne/java/org/apache/cayenne/ cayenne/java/org/apache/cayenne/access/ cayenne/java/org/apache/cayenne/map/ cayenne/java/org/apache/cayenne/query/ tests/java/org/apache/...

Author: aadamchik
Date: Wed Jul 19 19:33:25 2006
New Revision: 423717

URL: http://svn.apache.org/viewvc?rev=423717&view=rev
Log:
merging changes from 3.0 temporary branch. This patch fixes the issues
* CAY-576
* CAY-586

Added:
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/Validating.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/query/InvalidateListCacheQuery.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/CayenneContextValidationTst.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/query/InvalidateListCacheQueryTst.java
Removed:
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/access/ObjectStoreValidationTst.java
Modified:
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContext.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextGraphManager.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextQueryAction.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneDataObject.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/DataObject.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ClientServerChannel.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataContextQueryAction.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataDomainQueryAction.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataRowStore.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStore.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/map/EntityDescriptor.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/art/MixedPersistenceStrategy2.java
    incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/testdo/mt/ClientMtTable1.java

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContext.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContext.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContext.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContext.java Wed Jul 19 19:33:25 2006
@@ -21,6 +21,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.cayenne.event.EventManager;
@@ -32,6 +33,8 @@
 import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.util.EventUtil;
+import org.apache.cayenne.validation.ValidationException;
+import org.apache.cayenne.validation.ValidationResult;
 
 /**
  * A default generic implementation of ObjectContext suitable for accessing Cayenne from
@@ -181,21 +184,49 @@
      * service via an internal instance of CayenneConnector.
      */
     public void commitChanges() {
-        doCommitChanges();
+        doCommitChanges(true);
     }
 
-    GraphDiff doCommitChanges() {
+    GraphDiff doCommitChanges(boolean cascade) {
+
+        int syncType = cascade
+                ? DataChannel.FLUSH_CASCADE_SYNC
+                : DataChannel.FLUSH_NOCASCADE_SYNC;
+
         GraphDiff commitDiff = null;
 
         synchronized (graphManager) {
 
             if (graphManager.hasChanges()) {
 
+                ValidationResult result = new ValidationResult();
+                Iterator it = graphManager.dirtyNodes().iterator();
+                while (it.hasNext()) {
+                    Persistent p = (Persistent) it.next();
+                    if (p instanceof Validating) {
+                        switch (p.getPersistenceState()) {
+                            case PersistenceState.NEW:
+                                ((Validating) p).validateForInsert(result);
+                                break;
+                            case PersistenceState.MODIFIED:
+                                ((Validating) p).validateForUpdate(result);
+                                break;
+                            case PersistenceState.DELETED:
+                                ((Validating) p).validateForDelete(result);
+                                break;
+                        }
+                    }
+                }
+
+                if (result.hasFailures()) {
+                    throw new ValidationException(result);
+                }
+
                 graphManager.graphCommitStarted();
 
                 try {
                     commitDiff = channel.onSync(this, graphManager
-                            .getDiffsSinceLastFlush(), DataChannel.FLUSH_CASCADE_SYNC);
+                            .getDiffsSinceLastFlush(), syncType);
                 }
                 catch (Throwable th) {
                     graphManager.graphCommitAborted();
@@ -214,6 +245,10 @@
 
         return commitDiff;
     }
+    
+    public void commitChangesToParent() {
+        doCommitChanges(false);
+    }
 
     public void rollbackChanges() {
         synchronized (graphManager) {
@@ -223,16 +258,6 @@
                 graphManager.graphReverted();
 
                 channel.onSync(this, diff, DataChannel.ROLLBACK_CASCADE_SYNC);
-            }
-        }
-    }
-
-    public void commitChangesToParent() {
-        synchronized (graphManager) {
-            if (graphManager.hasChangesSinceLastFlush()) {
-                GraphDiff diff = graphManager.getDiffsSinceLastFlush();
-                graphManager.graphFlushed();
-                channel.onSync(this, diff, DataChannel.FLUSH_NOCASCADE_SYNC);
             }
         }
     }

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextGraphManager.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextGraphManager.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextGraphManager.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextGraphManager.java Wed Jul 19 19:33:25 2006
@@ -83,6 +83,13 @@
     synchronized List getCachedQueryResult(String name) {
         return (List) queryResultMap.get(name);
     }
+    
+    /**
+     * @since 3.0
+     */
+    Map getCachedQueryResults() {
+        return queryResultMap;
+    }
 
     boolean hasChangesSinceLastFlush() {
         int size = changeLog.hasMarker(FLUSH_MARKER) ? changeLog

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextQueryAction.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextQueryAction.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextQueryAction.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneContextQueryAction.java Wed Jul 19 19:33:25 2006
@@ -19,11 +19,15 @@
 
 package org.apache.cayenne;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.cayenne.query.InvalidateListCacheQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.remote.RemoteIncrementalFaultList;
+import org.apache.cayenne.util.GenericResponse;
 import org.apache.cayenne.util.ListResponse;
 import org.apache.cayenne.util.ObjectContextQueryAction;
 
@@ -42,9 +46,11 @@
 
         if (interceptOIDQuery() != DONE) {
             if (interceptRelationshipQuery() != DONE) {
-                if (interceptLocalCache() != DONE) {
-                    if (interceptPaginatedQuery() != DONE) {
-                        runQuery();
+                if (interceptInvalidateQuery() != DONE) {
+                    if (interceptLocalCache() != DONE) {
+                        if (interceptPaginatedQuery() != DONE) {
+                            runQuery();
+                        }
                     }
                 }
             }
@@ -97,5 +103,38 @@
 
         graphManager.cacheQueryResult(cacheKey, response.firstList());
         return DONE;
+    }
+    
+    private boolean interceptInvalidateQuery() {
+        if (query instanceof InvalidateListCacheQuery) {
+            InvalidateListCacheQuery invalidateQuery = (InvalidateListCacheQuery) query;
+
+            CayenneContextGraphManager graphManager = ((CayenneContext) actingContext)
+                    .internalGraphManager();
+
+            int count = 0;
+            synchronized (graphManager) {
+                Iterator it = graphManager.getCachedQueryResults().entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    if (invalidateQuery.matchesCacheKey((String) entry.getKey())) {
+                        count++;
+                        it.remove();
+                    }
+                }
+            }
+
+            if (invalidateQuery.isCascade()) {
+                return !DONE;
+            }
+            else {
+                GenericResponse response = new GenericResponse();
+                response.addUpdateCount(count);
+                this.response = response;
+                return DONE;
+            }
+        }
+
+        return !DONE;
     }
 }

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneDataObject.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneDataObject.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneDataObject.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/CayenneDataObject.java Wed Jul 19 19:33:25 2006
@@ -54,7 +54,7 @@
  * 
  * @author Andrei Adamchik
  */
-public class CayenneDataObject implements DataObject, XMLSerializable {
+public class CayenneDataObject implements DataObject, Validating, XMLSerializable {
 
     protected long snapshotVersion = DEFAULT_VERSION;
 

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/DataObject.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/DataObject.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/DataObject.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/DataObject.java Wed Jul 19 19:33:25 2006
@@ -20,7 +20,6 @@
 package org.apache.cayenne;
 
 import org.apache.cayenne.access.DataContext;
-import org.apache.cayenne.validation.ValidationResult;
 
 /**
  * Defines basic methods for a persistent object in Cayenne.
@@ -166,31 +165,4 @@
      * @deprecated since 1.2 use 'getObjectContext().prepareForAccess(object)'
      */
     public void resolveFault();
-
-    /**
-     * Performs property validation of the NEW object, appending any validation failures
-     * to the provided validationResult object. This method is invoked by DataContext
-     * before committing a NEW object to the database.
-     * 
-     * @since 1.1
-     */
-    public void validateForInsert(ValidationResult validationResult);
-
-    /**
-     * Performs property validation of the MODIFIED object, appending any validation
-     * failures to the provided validationResult object. This method is invoked by
-     * DataContext before committing a MODIFIED object to the database.
-     * 
-     * @since 1.1
-     */
-    public void validateForUpdate(ValidationResult validationResult);
-
-    /**
-     * Performs property validation of the DELETED object, appending any validation
-     * failures to the provided validationResult object. This method is invoked by
-     * DataContext before committing a DELETED object to the database.
-     * 
-     * @since 1.1
-     */
-    public void validateForDelete(ValidationResult validationResult);
 }

Added: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/Validating.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/Validating.java?rev=423717&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/Validating.java (added)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/Validating.java Wed Jul 19 19:33:25 2006
@@ -0,0 +1,52 @@
+/*****************************************************************
+ *   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;
+
+import org.apache.cayenne.validation.ValidationResult;
+
+/**
+ * Defines a number of callback methods that allow an object to be validated before safe.
+ * Entity class can implement this interface and its methods will be called automatically.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+public interface Validating {
+
+    /**
+     * Performs property validation of the NEW object, appending any validation failures
+     * to the provided validationResult object. This method is invoked by ObjectContext
+     * before committing a NEW object to the database.
+     */
+    public void validateForInsert(ValidationResult validationResult);
+
+    /**
+     * Performs property validation of the MODIFIED object, appending any validation
+     * failures to the provided validationResult object. This method is invoked by
+     * ObjectContext before committing a MODIFIED object to the database.
+     */
+    public void validateForUpdate(ValidationResult validationResult);
+
+    /**
+     * Performs property validation of the DELETED object, appending any validation
+     * failures to the provided validationResult object. This method is invoked by
+     * ObjectContext before committing a DELETED object to the database.
+     */
+    public void validateForDelete(ValidationResult validationResult);
+}

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ClientServerChannel.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ClientServerChannel.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ClientServerChannel.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ClientServerChannel.java Wed Jul 19 19:33:25 2006
@@ -19,8 +19,7 @@
 
 package org.apache.cayenne.access;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataChannel;
@@ -44,8 +43,7 @@
 
     protected DataContext serverContext;
     protected boolean lifecycleEventsEnabled;
-    protected Map paginatedResults;
-
+  
     public ClientServerChannel(DataDomain domain) {
         this(domain, false);
     }
@@ -63,17 +61,15 @@
         return new ClientServerChannelQueryAction(this, query).execute();
     }
 
-    synchronized void addPaginatedResult(String cacheKey, IncrementalFaultList result) {
-        if (paginatedResults == null) {
-            paginatedResults = new HashMap();
-        }
-
-        paginatedResults.put(cacheKey, result);
+    void addPaginatedResult(String cacheKey, IncrementalFaultList result) {
+        serverContext.getObjectStore().cacheQueryResult(cacheKey, result);
     }
 
-    synchronized IncrementalFaultList getPaginatedResult(String cacheKey) {
-        return (paginatedResults != null) ? (IncrementalFaultList) paginatedResults
-                .get(cacheKey) : null;
+    IncrementalFaultList getPaginatedResult(String cacheKey) {
+        List result = serverContext.getObjectStore().getCachedQueryResult(cacheKey);
+        return (result instanceof IncrementalFaultList)
+                ? (IncrementalFaultList) result
+                : null;
     }
 
     DataContext getServerContext() {

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataContextQueryAction.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataContextQueryAction.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataContextQueryAction.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataContextQueryAction.java Wed Jul 19 19:33:25 2006
@@ -19,14 +19,18 @@
 
 package org.apache.cayenne.access;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.QueryResponse;
+import org.apache.cayenne.query.InvalidateListCacheQuery;
+import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.QueryMetadata;
-import org.apache.cayenne.query.ObjectIdQuery;
+import org.apache.cayenne.util.GenericResponse;
 import org.apache.cayenne.util.ListResponse;
 import org.apache.cayenne.util.ObjectContextQueryAction;
 
@@ -50,8 +54,10 @@
         if (interceptPaginatedQuery() != DONE) {
             if (interceptOIDQuery() != DONE) {
                 if (interceptRelationshipQuery() != DONE) {
-                    if (interceptLocalCache() != DONE) {
-                        runQuery();
+                    if (interceptInvalidateQuery() != DONE) {
+                        if (interceptLocalCache() != DONE) {
+                            runQuery();
+                        }
                     }
                 }
             }
@@ -129,5 +135,37 @@
         runQuery();
         objectStore.cacheQueryResult(cacheKey, response.firstList());
         return DONE;
+    }
+
+    private boolean interceptInvalidateQuery() {
+        if (query instanceof InvalidateListCacheQuery) {
+            InvalidateListCacheQuery invalidateQuery = (InvalidateListCacheQuery) query;
+
+            ObjectStore objectStore = ((DataContext) actingContext).getObjectStore();
+
+            int count = 0;
+            synchronized (objectStore) {
+                Iterator it = objectStore.getCachedQueryResults().entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    if (invalidateQuery.matchesCacheKey((String) entry.getKey())) {
+                        count++;
+                        it.remove();
+                    }
+                }
+            }
+
+            if (invalidateQuery.isCascade()) {
+                return !DONE;
+            }
+            else {
+                GenericResponse response = new GenericResponse();
+                response.addUpdateCount(count);
+                this.response = response;
+                return DONE;
+            }
+        }
+
+        return !DONE;
     }
 }

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataDomainQueryAction.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataDomainQueryAction.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataDomainQueryAction.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataDomainQueryAction.java Wed Jul 19 19:33:25 2006
@@ -39,6 +39,7 @@
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.query.InvalidateListCacheQuery;
 import org.apache.cayenne.query.PrefetchSelectQuery;
 import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.Query;
@@ -105,8 +106,10 @@
         // run chain...
         if (interceptOIDQuery() != DONE) {
             if (interceptRelationshipQuery() != DONE) {
-                if (interceptSharedCache() != DONE) {
-                    runQueryInTransaction();
+                if (interceptInvalidateQuery() != DONE) {
+                    if (interceptSharedCache() != DONE) {
+                        runQueryInTransaction();
+                    }
                 }
             }
         }
@@ -231,6 +234,35 @@
         return !DONE;
     }
 
+    /**
+     * @since 3.0
+     */
+    private boolean interceptInvalidateQuery() {
+        if (query instanceof InvalidateListCacheQuery) {
+            InvalidateListCacheQuery invalidateQuery = (InvalidateListCacheQuery) query;
+
+            int count = 0;
+            synchronized (cache) {
+                Iterator it = cache.getCachedSnapshots().entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry entry = (Map.Entry) it.next();
+                    if (invalidateQuery.matchesCacheKey((String) entry.getKey())) {
+                        count++;
+                        it.remove();
+                    }
+                }
+            }
+
+            // ignore 'cascade' setting - we are at the bottom of the stack already...
+            GenericResponse response = new GenericResponse();
+            response.addUpdateCount(count);
+            this.response = response;
+            return DONE;
+        }
+
+        return !DONE;
+    }
+    
     /*
      * Wraps execution in shared cache checks
      */

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataRowStore.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataRowStore.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataRowStore.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/DataRowStore.java Wed Jul 19 19:33:25 2006
@@ -408,6 +408,13 @@
             return snapshot;
         }
     }
+    
+    /**
+     * @since 3.0
+     */
+    Map getCachedSnapshots() {
+        return snapshotLists;
+    }
 
     /**
      * Registers a list of snapshots with internal cache, using a String key.

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStore.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStore.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStore.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStore.java Wed Jul 19 19:33:25 2006
@@ -48,8 +48,6 @@
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
 import org.apache.cayenne.query.ObjectIdQuery;
-import org.apache.cayenne.validation.ValidationException;
-import org.apache.cayenne.validation.ValidationResult;
 
 /**
  * ObjectStore stores objects using their ObjectId as a key. It works as a dedicated
@@ -662,6 +660,13 @@
         // they were originally cached... do no conversions here
         return (List) queryResultMap.get(name);
     }
+    
+    /**
+     * @since 3.0
+     */
+    Map getCachedQueryResults() {
+        return queryResultMap;
+    }
 
     /**
      * Caches a list of query results.
@@ -804,83 +809,6 @@
                 ? (ObjectContext) event.getPostedBy()
                 : null;
         context.fireDataChannelChanged(originatingContext, diff);
-    }
-
-    /**
-     * Performs validation of all uncommitted objects in the ObjectStore. If validation
-     * fails, a ValidationException is thrown, listing all encountered failures. This is a
-     * utility method for the users to call. Cayenne itself uses a different mechanism to
-     * validate objects on commit.
-     * 
-     * @since 1.1
-     * @throws ValidationException
-     * @deprecated since 1.2 - This method is no longer used in Cayenne internally.
-     */
-    public synchronized void validateUncommittedObjects() throws ValidationException {
-
-        // we must iterate over a copy of object list,
-        // as calling validateFor* on DataObjects can have a side effect
-        // of modifying this ObjectStore, and thus resulting in
-        // ConcurrentModificationExceptions in the Iterator
-
-        Collection deleted = null;
-        Collection inserted = null;
-        Collection updated = null;
-
-        Iterator allIt = getObjectIterator();
-        while (allIt.hasNext()) {
-            DataObject dataObject = (DataObject) allIt.next();
-            switch (dataObject.getPersistenceState()) {
-                case PersistenceState.NEW:
-                    if (inserted == null) {
-                        inserted = new ArrayList();
-                    }
-                    inserted.add(dataObject);
-                    break;
-                case PersistenceState.MODIFIED:
-                    if (updated == null) {
-                        updated = new ArrayList();
-                    }
-                    updated.add(dataObject);
-                    break;
-                case PersistenceState.DELETED:
-                    if (deleted == null) {
-                        deleted = new ArrayList();
-                    }
-                    deleted.add(dataObject);
-                    break;
-            }
-        }
-
-        ValidationResult validationResult = new ValidationResult();
-
-        if (deleted != null) {
-            Iterator it = deleted.iterator();
-            while (it.hasNext()) {
-                DataObject dataObject = (DataObject) it.next();
-                dataObject.validateForDelete(validationResult);
-            }
-        }
-
-        if (inserted != null) {
-            Iterator it = inserted.iterator();
-            while (it.hasNext()) {
-                DataObject dataObject = (DataObject) it.next();
-                dataObject.validateForInsert(validationResult);
-            }
-        }
-
-        if (updated != null) {
-            Iterator it = updated.iterator();
-            while (it.hasNext()) {
-                DataObject dataObject = (DataObject) it.next();
-                dataObject.validateForUpdate(validationResult);
-            }
-        }
-
-        if (validationResult.hasFailures()) {
-            throw new ValidationException(validationResult);
-        }
     }
 
     /**

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/access/ObjectStoreGraphDiff.java Wed Jul 19 19:33:25 2006
@@ -25,10 +25,10 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cayenne.DataObject;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.Persistent;
+import org.apache.cayenne.Validating;
 import org.apache.cayenne.graph.CompoundDiff;
 import org.apache.cayenne.graph.GraphChangeHandler;
 import org.apache.cayenne.graph.GraphDiff;
@@ -77,17 +77,20 @@
                 noop = false;
 
                 // accessing objectMap directly to avoid unneeded synchronization.
-                DataObject object = (DataObject) objectStore.getNodeNoSync(entry.getKey());
-                switch (object.getPersistenceState()) {
-                    case PersistenceState.NEW:
-                        object.validateForInsert(result);
-                        break;
-                    case PersistenceState.MODIFIED:
-                        object.validateForUpdate(result);
-                        break;
-                    case PersistenceState.DELETED:
-                        object.validateForDelete(result);
-                        break;
+                Persistent object = (Persistent) objectStore.getNodeNoSync(entry.getKey());
+                
+                if (object instanceof Validating) {
+                    switch (object.getPersistenceState()) {
+                        case PersistenceState.NEW:
+                            ((Validating) object).validateForInsert(result);
+                            break;
+                        case PersistenceState.MODIFIED:
+                            ((Validating) object).validateForUpdate(result);
+                            break;
+                        case PersistenceState.DELETED:
+                            ((Validating) object).validateForDelete(result);
+                            break;
+                    }
                 }
             }
         }

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/map/EntityDescriptor.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/map/EntityDescriptor.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/map/EntityDescriptor.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/map/EntityDescriptor.java Wed Jul 19 19:33:25 2006
@@ -252,10 +252,12 @@
         }
     }
 
-    /*
-     * Creates an accessor for the property.
+    /**
+     * Creates an accessor for the property. By default uses uses
+     * {@link DataObjectAccessor} for DataObjects and {@link FieldAccessor} for all other
+     * classes.
      */
-    PropertyAccessor makeAccessor(String propertyName, Class propertyType)
+    protected PropertyAccessor makeAccessor(String propertyName, Class propertyType)
             throws PropertyAccessException {
 
         if (dataObject) {

Added: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/query/InvalidateListCacheQuery.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/query/InvalidateListCacheQuery.java?rev=423717&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/query/InvalidateListCacheQuery.java (added)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/apache/cayenne/query/InvalidateListCacheQuery.java Wed Jul 19 19:33:25 2006
@@ -0,0 +1,125 @@
+/*****************************************************************
+ *   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.query;
+
+import java.util.regex.Pattern;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.map.EntityResolver;
+
+/**
+ * A Query that allows to clear list caches. Lists to invalidate are located by matching a
+ * regex pattern against the cache key. For non-cascading query result returned from the
+ * query execution is the number of cached invalidated lists. For cascading query the
+ * result is undefined.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+public class InvalidateListCacheQuery implements Query {
+
+    protected String cacheKeyPattern;
+    protected boolean cascade;
+
+    protected transient Pattern cacheKeyCompiledPattern;
+
+    // needed for hessian serialization
+    private InvalidateListCacheQuery() {
+
+    }
+
+    /**
+     * Creates a new InvalidateCacheQuery.
+     * 
+     * @param cacheKeyPattern a String that can be compiled to a valid
+     *            java.regex.util.Pattern that will be used to match against query cache
+     *            keys.
+     * @param cascade whether to invalidate cache in the local ObjectContext, or to
+     *            propagate the operation through the entire stack.
+     */
+    public InvalidateListCacheQuery(String cacheKeyPattern, boolean cascade) {
+        this.cacheKeyPattern = cacheKeyPattern;
+        this.cascade = cascade;
+    }
+
+    public boolean isCascade() {
+        return cascade;
+    }
+
+    public Pattern getCacheKeyCompiledPattern() {
+
+        // compiling pattern lazily is good for serialization
+        if (cacheKeyCompiledPattern == null) {
+            cacheKeyCompiledPattern = Pattern.compile(cacheKeyPattern);
+        }
+
+        return cacheKeyCompiledPattern;
+    }
+
+    public String getCacheKeyPattern() {
+        return cacheKeyPattern;
+    }
+
+    /**
+     * Returns true if the cache key argument matches the pattern.
+     */
+    public boolean matchesCacheKey(String cacheKey) {
+        return cacheKey == null ? false : getCacheKeyCompiledPattern()
+                .matcher(cacheKey)
+                .matches();
+    }
+
+    public QueryMetadata getMetaData(EntityResolver resolver) {
+        return new BaseQueryMetadata();
+    }
+
+    public String getName() {
+        return null;
+    }
+
+    /**
+     * @deprecated since 1.2
+     */
+    public Object getRoot() {
+        return null;
+    }
+
+    public void route(QueryRouter router, EntityResolver resolver, Query substitutedQuery) {
+        // noop
+    }
+
+    public SQLAction createSQLAction(SQLActionVisitor visitor) {
+        throw new CayenneRuntimeException("Unsupported operation");
+    }
+
+    /**
+     * @deprecated since 1.2
+     */
+    public void setName(String name) {
+        // noop
+    }
+
+    /**
+     * @deprecated since 1.2
+     */
+    public void setRoot(Object root) {
+        // noop
+    }
+
+}

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/art/MixedPersistenceStrategy2.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/art/MixedPersistenceStrategy2.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/art/MixedPersistenceStrategy2.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/art/MixedPersistenceStrategy2.java Wed Jul 19 19:33:25 2006
@@ -4,7 +4,4 @@
 
 public class MixedPersistenceStrategy2 extends _MixedPersistenceStrategy2 {
 
-}
-
-
-
+}
\ No newline at end of file

Added: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/CayenneContextValidationTst.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/CayenneContextValidationTst.java?rev=423717&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/CayenneContextValidationTst.java (added)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/CayenneContextValidationTst.java Wed Jul 19 19:33:25 2006
@@ -0,0 +1,91 @@
+/*****************************************************************
+ *   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;
+
+import org.apache.cayenne.access.ClientServerChannel;
+import org.apache.cayenne.remote.ClientChannel;
+import org.apache.cayenne.remote.service.LocalConnection;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.unit.AccessStack;
+import org.apache.cayenne.unit.CayenneTestCase;
+import org.apache.cayenne.unit.CayenneTestResources;
+import org.apache.cayenne.validation.ValidationException;
+
+public class CayenneContextValidationTst extends CayenneTestCase {
+
+    protected AccessStack buildAccessStack() {
+        return CayenneTestResources
+                .getResources()
+                .getAccessStack(MULTI_TIER_ACCESS_STACK);
+    }
+
+    public void testValidate() throws Exception {
+
+        deleteTestData();
+        DataChannel serverChannel = new ClientServerChannel(getDomain(), false);
+        ClientChannel clientChannel = new ClientChannel(
+                new LocalConnection(serverChannel),
+                true);
+
+        CayenneContext c = new CayenneContext(clientChannel);
+        
+        ClientMtTable1 o1 = (ClientMtTable1) c.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("G1");
+        o1.resetValidation(false);
+        
+        // this one is not validating
+        ClientMtTable2 o2 = (ClientMtTable2) c.newObject(ClientMtTable2.class);
+        o2.setTable1(o1);
+        
+        c.commitChanges();
+        assertTrue(o1.isValidatedForInsert());
+        assertFalse(o1.isValidatedForDelete());
+        assertFalse(o1.isValidatedForUpdate());
+        
+        o1.resetValidation(false);
+        o1.setGlobalAttribute1("G2");
+        
+        c.commitChanges();
+        assertFalse(o1.isValidatedForInsert());
+        assertFalse(o1.isValidatedForDelete());
+        assertTrue(o1.isValidatedForUpdate());
+        
+        o1.resetValidation(false);
+        c.deleteObject(o1);
+        
+        c.commitChanges();
+        assertFalse(o1.isValidatedForInsert());
+        assertTrue(o1.isValidatedForDelete());
+        assertFalse(o1.isValidatedForUpdate());
+        
+        ClientMtTable1 o11 = (ClientMtTable1) c.newObject(ClientMtTable1.class);
+        o11.setGlobalAttribute1("G1");
+        o11.resetValidation(true);
+        
+        try {
+            c.commitChanges();
+            fail("Validation failure must have prevented commit");
+        }
+        catch (ValidationException e) {
+           // expected
+        }
+    }
+}
\ No newline at end of file

Added: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/query/InvalidateListCacheQueryTst.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/query/InvalidateListCacheQueryTst.java?rev=423717&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/query/InvalidateListCacheQueryTst.java (added)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/query/InvalidateListCacheQueryTst.java Wed Jul 19 19:33:25 2006
@@ -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.query;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.remote.hessian.service.HessianUtil;
+
+public class InvalidateListCacheQueryTst extends TestCase {
+
+    public void testMatchesCacheKey() {
+
+        InvalidateListCacheQuery q1 = new InvalidateListCacheQuery("abc.", true);
+
+        assertTrue(q1.matchesCacheKey("abcd"));
+        assertTrue(q1.matchesCacheKey("abc4"));
+
+        assertFalse(q1.matchesCacheKey("abcde"));
+        assertFalse(q1.matchesCacheKey("abc"));
+        assertFalse(q1.matchesCacheKey("xxxx"));
+        
+        InvalidateListCacheQuery q2 = new InvalidateListCacheQuery("abc.*", true);
+
+        assertTrue(q2.matchesCacheKey("abcd"));
+        assertTrue(q2.matchesCacheKey("abc4"));
+
+        assertTrue(q2.matchesCacheKey("abcde"));
+        assertTrue(q2.matchesCacheKey("abc"));
+        
+        assertFalse(q2.matchesCacheKey("xxxx"));
+    }
+
+    public void testSerializabilityWithHessian() throws Exception {
+        InvalidateListCacheQuery o = new InvalidateListCacheQuery("XXX", true);
+        Object clone = HessianUtil.cloneViaClientServerSerialization(
+                o,
+                new EntityResolver());
+
+        assertTrue(clone instanceof InvalidateListCacheQuery);
+        InvalidateListCacheQuery c1 = (InvalidateListCacheQuery) clone;
+
+        assertNotSame(o, c1);
+        assertEquals(o.getCacheKeyPattern(), c1.getCacheKeyPattern());
+        assertTrue(c1.isCascade());
+    }
+}

Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/testdo/mt/ClientMtTable1.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/testdo/mt/ClientMtTable1.java?rev=423717&r1=423716&r2=423717&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/testdo/mt/ClientMtTable1.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/tests/java/org/apache/cayenne/testdo/mt/ClientMtTable1.java Wed Jul 19 19:33:25 2006
@@ -2,9 +2,17 @@
 
 import java.util.List;
 
+import org.apache.cayenne.Validating;
 import org.apache.cayenne.testdo.mt.auto._ClientMtTable1;
+import org.apache.cayenne.validation.SimpleValidationFailure;
+import org.apache.cayenne.validation.ValidationResult;
 
-public class ClientMtTable1 extends _ClientMtTable1 {
+public class ClientMtTable1 extends _ClientMtTable1 implements Validating {
+    
+    protected boolean validatedForDelete;
+    protected boolean validatedForInsert;
+    protected boolean validatedForUpdate;
+    protected boolean blow;
 
     // provide direct access to persistent properties for testing..
 
@@ -19,5 +27,50 @@
     public List getTable2ArrayDirect() {
         return table2Array;
     }
+    
+    public void resetValidation(boolean blow) {
+        this.blow = blow;
+        this.validatedForDelete = false;
+        this.validatedForInsert = false;
+        this.validatedForUpdate = false;
+    }
+
+    public void validateForDelete(ValidationResult validationResult) {
+        validatedForDelete = true;
+        
+        if(blow) {
+            validationResult.addFailure(new SimpleValidationFailure(this, "test error"));
+        }
+    }
+
+    public void validateForInsert(ValidationResult validationResult) {
+        validatedForInsert = true;
+        
+        if(blow) {
+            validationResult.addFailure(new SimpleValidationFailure(this, "test error"));
+        }
+    }
+
+    public void validateForUpdate(ValidationResult validationResult) {
+        validatedForUpdate = true;
+        
+        if(blow) {
+            validationResult.addFailure(new SimpleValidationFailure(this, "test error"));
+        }
+    }
+
+    
+    public boolean isValidatedForDelete() {
+        return validatedForDelete;
+    }
 
+    
+    public boolean isValidatedForInsert() {
+        return validatedForInsert;
+    }
+
+    
+    public boolean isValidatedForUpdate() {
+        return validatedForUpdate;
+    }
 }