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 2010/11/14 10:42:41 UTC

svn commit: r1034965 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src: main/java/org/apache/cayenne/ main/java/org/apache/cayenne/access/ main/java/org/apache/cayenne/configuration/server/ test/java/org/apache/cayenne/ test/java/org/ap...

Author: aadamchik
Date: Sun Nov 14 09:42:40 2010
New Revision: 1034965

URL: http://svn.apache.org/viewvc?rev=1034965&view=rev
Log:
CAY-1508 Support for DataChannel filters

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilter.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilterChain.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockDataChannelFilter.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataDomainFiltersTest.java
Modified:
    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/configuration/server/DataDomainProvider.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/UnitTestDomain.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilter.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilter.java?rev=1034965&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilter.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilter.java Sun Nov 14 09:42:40 2010
@@ -0,0 +1,46 @@
+/*****************************************************************
+ *   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.graph.GraphDiff;
+import org.apache.cayenne.query.Query;
+
+/**
+ * An interface of a filter that allows to intercept DataChannel operations. Filters allow
+ * to implement chains of custom processors around a DataChannel, that can be used for
+ * security, monitoring, business logic, providing context to lifecycle event listeners,
+ * etc.
+ * 
+ * @since 3.1
+ */
+public interface DataChannelFilter {
+    
+    void init(DataChannel channel);
+
+    QueryResponse onQuery(
+            ObjectContext originatingContext,
+            Query query,
+            DataChannelFilterChain filterChain);
+
+    GraphDiff onSync(
+            ObjectContext originatingContext,
+            GraphDiff changes,
+            int syncType,
+            DataChannelFilterChain filterChain);
+}

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilterChain.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilterChain.java?rev=1034965&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilterChain.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelFilterChain.java Sun Nov 14 09:42:40 2010
@@ -0,0 +1,35 @@
+/*****************************************************************
+ *   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.graph.GraphDiff;
+import org.apache.cayenne.query.Query;
+
+/**
+ * Provides DataChannelFilters with API to pass control to the next filter in the chain or
+ * the underlying DataChannel for the last chain filter.
+ * 
+ * @since 3.1
+ */
+public interface DataChannelFilterChain {
+
+    QueryResponse onQuery(ObjectContext originatingContext, Query query);
+
+    GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType);
+}

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java?rev=1034965&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java Sun Nov 14 09:42:40 2010
@@ -0,0 +1,26 @@
+/*****************************************************************
+ *   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.graph.GraphDiff;
+
+public interface DataChannelSyncFilterChain {
+
+    GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType);
+}

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=1034965&r1=1034964&r2=1034965&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 Sun Nov 14 09:42:40 2010
@@ -23,11 +23,14 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.DataChannelFilter;
+import org.apache.cayenne.DataChannelFilterChain;
 import org.apache.cayenne.DataChannelSyncCallbackAction;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.QueryResponse;
@@ -73,9 +76,17 @@ public class DataDomain implements Query
      */
     public static final String QUERY_CACHE_FACTORY_PROPERTY = "cayenne.DataDomain.queryCacheFactory";
 
+    /**
+     * @since 3.1
+     */
     @Inject
     protected JdbcEventLogger jdbcEventLogger;
 
+    /**
+     * @since 3.1
+     */
+    protected List<DataChannelFilter> filters;
+
     /** Stores mapping of data nodes to DataNode name keys. */
     protected Map<String, DataNode> nodes = Collections
             .synchronizedMap(new TreeMap<String, DataNode>());
@@ -713,14 +724,21 @@ public class DataDomain implements Query
      * 
      * @since 1.2
      */
-    public QueryResponse onQuery(final ObjectContext context, final Query query) {
+    public QueryResponse onQuery(final ObjectContext originatingContext, final Query query) {
         checkStopped();
 
+        return new DataDomainQueryFilterChain().onQuery(originatingContext, query);
+    }
+
+    QueryResponse onQueryNoFilters(
+            final ObjectContext originatingContext,
+            final Query query) {
         // transaction note:
         // we don't wrap this code in transaction to reduce transaction scope to
-        // just the DB operation for better performance ... query action will start a
-        // transaction itself when and if needed
-        return new DataDomainQueryAction(context, DataDomain.this, query).execute();
+        // just the DB operation for better performance ... query action will
+        // start a transaction itself when and if needed
+        return new DataDomainQueryAction(originatingContext, DataDomain.this, query)
+                .execute();
     }
 
     /**
@@ -746,6 +764,16 @@ public class DataDomain implements Query
 
         checkStopped();
 
+        return new DataDomainSyncFilterChain().onSync(
+                originatingContext,
+                changes,
+                syncType);
+    }
+
+    GraphDiff onSyncNoFilters(
+            final ObjectContext originatingContext,
+            final GraphDiff changes,
+            int syncType) {
         DataChannelSyncCallbackAction callbackAction = DataChannelSyncCallbackAction
                 .getCallbackAction(
                         getEntityResolver().getCallbackRegistry(),
@@ -920,10 +948,79 @@ public class DataDomain implements Query
     public BatchQueryBuilderFactory getQueryBuilderFactory() {
         return queryBuilderFactory;
     }
-    
+
     void refreshEntitySorter() {
-        if(entitySorter != null) {
+        if (entitySorter != null) {
             entitySorter.setDataMaps(getDataMaps());
         }
     }
+
+    /**
+     * @since 3.1
+     */
+    public List<DataChannelFilter> getFilters() {
+        return filters;
+    }
+
+    /**
+     * @since 3.1
+     */
+    public void setFilters(List<DataChannelFilter> filters) {
+        this.filters = filters;
+    }
+
+    abstract class DataDomainFilterChain implements DataChannelFilterChain {
+
+        private int i;
+
+        DataDomainFilterChain() {
+            i = filters != null ? filters.size() : 0;
+        }
+
+        DataChannelFilter nextFilter() {
+            // filters are ordered innermost to outermost
+            i--;
+            return i >= 0 ? filters.get(i) : null;
+        }
+    }
+
+    final class DataDomainQueryFilterChain extends DataDomainFilterChain {
+
+        public QueryResponse onQuery(ObjectContext originatingContext, Query query) {
+
+            DataChannelFilter filter = nextFilter();
+            return (filter != null)
+                    ? filter.onQuery(originatingContext, query, this)
+                    : onQueryNoFilters(originatingContext, query);
+        }
+
+        public GraphDiff onSync(
+                ObjectContext originatingContext,
+                GraphDiff changes,
+                int syncType) {
+            throw new UnsupportedOperationException(
+                    "It is illegal to call 'onSync' inside 'onQuery' chain");
+        }
+    }
+
+    final class DataDomainSyncFilterChain extends DataDomainFilterChain {
+
+        public GraphDiff onSync(
+                final ObjectContext originatingContext,
+                final GraphDiff changes,
+                int syncType) {
+
+            DataChannelFilter filter = nextFilter();
+            return (filter != null) ? filter.onSync(
+                    originatingContext,
+                    changes,
+                    syncType,
+                    this) : onSyncNoFilters(originatingContext, changes, syncType);
+        }
+
+        public QueryResponse onQuery(ObjectContext originatingContext, Query query) {
+            throw new UnsupportedOperationException(
+                    "It is illegal to call 'onQuery' inside 'onSync' chain");
+        }
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java Sun Nov 14 09:42:40 2010
@@ -19,11 +19,13 @@
 package org.apache.cayenne.configuration.server;
 
 import java.util.Collection;
+import java.util.List;
 
 import javax.sql.DataSource;
 
 import org.apache.cayenne.ConfigurationException;
 import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.DataChannelFilter;
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
@@ -54,6 +56,11 @@ public class DataDomainProvider implemen
 
     private static Log logger = LogFactory.getLog(DataDomainProvider.class);
 
+    /**
+     * A DI key for the list storing DataDomain filters.
+     */
+    public static final String FILTERS_LIST = "org.apache.cayenne.configuration.server.DataDomainProvider.filters";
+
     @Inject
     protected ResourceLocator resourceLocator;
 
@@ -75,6 +82,9 @@ public class DataDomainProvider implemen
     @Inject
     protected AdhocObjectFactory objectFactory;
 
+    @Inject(FILTERS_LIST)
+    protected List<DataChannelFilter> filters;
+
     @Inject
     protected Injector injector;
 
@@ -91,7 +101,7 @@ public class DataDomainProvider implemen
                     .getMessage());
         }
     }
-    
+
     protected DataDomain createDataDomain(String name) {
         return new DataDomain(name);
     }
@@ -151,7 +161,7 @@ public class DataDomainProvider implemen
 
         DataChannelDescriptor descriptor = tree.getRootNode();
         DataDomain dataDomain = createDataDomain(descriptor.getName());
-        
+
         dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
         dataDomain.setEventManager(injector.getInstance(EventManager.class));
 
@@ -203,6 +213,12 @@ public class DataDomainProvider implemen
             dataDomain.addNode(dataNode);
         }
 
+        for (DataChannelFilter filter : filters) {
+            filter.init(dataDomain);
+        }
+
+        dataDomain.setFilters(filters);
+
         return dataDomain;
     }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java Sun Nov 14 09:42:40 2010
@@ -104,6 +104,9 @@ public class ServerModule implements Mod
                 .add(new OracleSniffer())
                 .add(new PostgresSniffer())
                 .add(new MySQLSniffer());
+        
+        // configure an empty filter chain
+        binder.bindList(DataDomainProvider.FILTERS_LIST);
 
         binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
         binder.bind(ConfigurationNameMapper.class).to(

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockDataChannelFilter.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockDataChannelFilter.java?rev=1034965&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockDataChannelFilter.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/MockDataChannelFilter.java Sun Nov 14 09:42:40 2010
@@ -0,0 +1,44 @@
+/*****************************************************************
+ *   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.graph.GraphDiff;
+import org.apache.cayenne.query.Query;
+
+public class MockDataChannelFilter implements DataChannelFilter {
+
+    public void init(DataChannel channel) {
+    }
+
+    public QueryResponse onQuery(
+            ObjectContext originatingContext,
+            Query query,
+            DataChannelFilterChain filterChain) {
+        return null;
+    }
+
+    public GraphDiff onSync(
+            ObjectContext originatingContext,
+            GraphDiff changes,
+            int syncType,
+            DataChannelFilterChain filterChain) {
+        return null;
+    }
+
+}

Added: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataDomainFiltersTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataDomainFiltersTest.java?rev=1034965&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataDomainFiltersTest.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/DataDomainFiltersTest.java Sun Nov 14 09:42:40 2010
@@ -0,0 +1,200 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.access;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cayenne.DataChannelFilter;
+import org.apache.cayenne.DataChannelFilterChain;
+import org.apache.cayenne.MockDataChannelFilter;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.QueryResponse;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.util.ListResponse;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataDomainFiltersTest extends ServerCase {
+
+    @Inject
+    private ObjectContext context;
+
+    @Inject
+    private ServerRuntime runtime;
+
+    public void testDefaultNoFilters() {
+
+        DataDomain domain = runtime.getDataDomain();
+        assertEquals(0, domain.filters.size());
+    }
+
+    public void testOnQuery_FilterOrdering() {
+
+        DataDomain domain = runtime.getDataDomain();
+
+        final List<String> results = new ArrayList<String>();
+
+        DataChannelFilter f1 = new MockDataChannelFilter() {
+
+            @Override
+            public QueryResponse onQuery(
+                    ObjectContext originatingContext,
+                    Query query,
+                    DataChannelFilterChain filterChain) {
+
+                results.add("f1start");
+                QueryResponse response = filterChain.onQuery(originatingContext, query);
+                results.add("f1end");
+                return response;
+            }
+        };
+
+        DataChannelFilter f2 = new MockDataChannelFilter() {
+
+            @Override
+            public QueryResponse onQuery(
+                    ObjectContext originatingContext,
+                    Query query,
+                    DataChannelFilterChain filterChain) {
+
+                results.add("f2start");
+                QueryResponse response = filterChain.onQuery(originatingContext, query);
+                results.add("f2end");
+                return response;
+            }
+        };
+
+        domain.filters.add(f1);
+        domain.filters.add(f2);
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        QueryResponse response = domain.onQuery(context, query);
+        assertNotNull(response);
+        assertEquals(4, results.size());
+        assertEquals("f2start", results.get(0));
+        assertEquals("f1start", results.get(1));
+        assertEquals("f1end", results.get(2));
+        assertEquals("f2end", results.get(3));
+    }
+
+    public void testOnSync_FilterOrdering() {
+
+        DataDomain domain = runtime.getDataDomain();
+
+        final List<String> results = new ArrayList<String>();
+
+        DataChannelFilter f1 = new MockDataChannelFilter() {
+
+            @Override
+            public GraphDiff onSync(
+                    ObjectContext originatingContext,
+                    GraphDiff changes,
+                    int syncType,
+                    DataChannelFilterChain filterChain) {
+
+                results.add("f1start");
+                GraphDiff response = filterChain.onSync(
+                        originatingContext,
+                        changes,
+                        syncType);
+                results.add("f1end");
+                return response;
+            }
+        };
+
+        DataChannelFilter f2 = new MockDataChannelFilter() {
+
+            @Override
+            public GraphDiff onSync(
+                    ObjectContext originatingContext,
+                    GraphDiff changes,
+                    int syncType,
+                    DataChannelFilterChain filterChain) {
+
+                results.add("f2start");
+                GraphDiff response = filterChain.onSync(
+                        originatingContext,
+                        changes,
+                        syncType);
+                results.add("f2end");
+                return response;
+            }
+        };
+
+        domain.filters.add(f1);
+        domain.filters.add(f2);
+
+        Artist a = context.newObject(Artist.class);
+        a.setArtistName("AAA");
+
+        // testing domain.onSync indirectly
+        context.commitChanges();
+        assertEquals(4, results.size());
+        assertEquals("f2start", results.get(0));
+        assertEquals("f1start", results.get(1));
+        assertEquals("f1end", results.get(2));
+        assertEquals("f2end", results.get(3));
+    }
+
+    public void testOnQuery_Blocking() {
+
+        DataDomain domain = runtime.getDataDomain();
+
+        final QueryResponse r1 = new ListResponse();
+        final QueryResponse r2 = new ListResponse();
+
+        DataChannelFilter f1 = new MockDataChannelFilter() {
+
+            @Override
+            public QueryResponse onQuery(
+                    ObjectContext originatingContext,
+                    Query query,
+                    DataChannelFilterChain filterChain) {
+
+                return r1;
+            }
+        };
+
+        DataChannelFilter f2 = new MockDataChannelFilter() {
+
+            @Override
+            public QueryResponse onQuery(
+                    ObjectContext originatingContext,
+                    Query query,
+                    DataChannelFilterChain filterChain) {
+
+                return r2;
+            }
+        };
+
+        domain.filters.add(f1);
+        domain.filters.add(f2);
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        QueryResponse response = domain.onQuery(context, query);
+        assertSame(r2, response);
+    }
+}

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/UnitTestDomain.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/UnitTestDomain.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/UnitTestDomain.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/UnitTestDomain.java Sun Nov 14 09:42:40 2010
@@ -59,8 +59,8 @@ public class UnitTestDomain extends Data
     }
 
     @Override
-    public QueryResponse onQuery(ObjectContext context, Query query) {
-        return new UnitTestDomainQueryAction(context, this, query).execute();
+    QueryResponse onQueryNoFilters(ObjectContext originatingContext, Query query) {
+        return new UnitTestDomainQueryAction(originatingContext, this, query).execute();
     }
 
     @Override

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java Sun Nov 14 09:42:40 2010
@@ -118,6 +118,7 @@ public class DataDomainProviderTest exte
         Module testModule = new Module() {
 
             public void configure(Binder binder) {
+                binder.bindList(DataDomainProvider.FILTERS_LIST);
                 binder.bind(EventManager.class).toInstance(eventManager);
                 binder.bind(EntitySorter.class).toInstance(new AshwoodEntitySorter());
                 binder.bind(ResourceLocator.class).toInstance(locator);

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java Sun Nov 14 09:42:40 2010
@@ -18,11 +18,9 @@
  ****************************************************************/
 package org.apache.cayenne.unit.di.server;
 
-import org.apache.cayenne.access.QueryLogger;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.spi.DefaultScope;
-import org.apache.cayenne.log.CommonsJdbcEventLogger;
 import org.apache.cayenne.unit.CayenneResources;
 import org.apache.cayenne.unit.di.DICase;
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java?rev=1034965&r1=1034964&r2=1034965&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java Sun Nov 14 09:42:40 2010
@@ -23,7 +23,6 @@ import javax.sql.DataSource;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.QueryLogger;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.di.Binder;