CAY-2438 Split DataChannel filter into two independent filters
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/b2d3b393 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/b2d3b393 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/b2d3b393 Branch: refs/heads/master Commit: b2d3b393610652ab3d51bf88c43c80b324ef0820 Parents: 7475b4e Author: Nikita Timofeev <stari...@gmail.com> Authored: Wed May 30 14:38:23 2018 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Fri Jun 8 16:18:39 2018 +0300 ---------------------------------------------------------------------- RELEASE-NOTES.txt | 1 + UPGRADE.txt | 6 ++- .../apache/cayenne/DataChannelQueryFilter.java | 24 +++++++++++ .../cayenne/DataChannelQueryFilterChain.java | 2 + .../apache/cayenne/DataChannelSyncFilter.java | 34 +++++++++++++++ .../cayenne/DataChannelSyncFilterChain.java | 5 +++ .../org/apache/cayenne/access/DataDomain.java | 12 ++++-- .../cayenne/access/DataDomainFiltersIT.java | 45 ++++++++++++++++++++ 8 files changed, 124 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/RELEASE-NOTES.txt ---------------------------------------------------------------------- diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index b7d8a7c..482f979 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -35,6 +35,7 @@ CAY-2414 Modeler: new icon design CAY-2415 Transaction isolation and propagation support CAY-2416 Change TreeMap for HashMap to store data in Cayenne model classes CAY-2422 Modeler: Open driver setup window on driver load error +CAY-2438 Split DataChannel filter into two independent filters CAY-2440 cdbimport: allow cross-schema relationships Bug Fixes: http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/UPGRADE.txt ---------------------------------------------------------------------- diff --git a/UPGRADE.txt b/UPGRADE.txt index 6b2f3d1..2dfbd9b 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -5,7 +5,11 @@ IMPORTANT: be sure to read all notes for the intermediate releases between your current release and the release you are upgrading to. ------------------------------------------------------------------------------- UPGRADING TO 4.1.M2 -* Per CAY-2400 Cayenne-DBCP2 was deprecated + +* Per CAY-2438 DataChannelFilter filter was deprecated and two new independent filters are introduced: + DataChannelSyncFilter and DataChannelQueryFilter. + +* Per CAY-2400 Cayenne-DBCP2 integration was deprecated * Per CAY-2377 All code deprecated in Cayenne 4.0 was removed, please review your code before upgrading. http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilter.java b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilter.java index 04f0ef1..ec1b55f 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilter.java @@ -22,11 +22,35 @@ package org.apache.cayenne; import org.apache.cayenne.query.Query; /** + * An interface of a filter that allows to intercept DataChannel query operations. + * Query filters allow to implement chains of custom processors around a DataChannel. + * <p> + * Example: <pre>{@code + * public class MyQueryFilter implements DataChannelQueryFilter { + * public QueryResponse onQuery(ObjectContext originatingContext, Query query, + * DataChannelQueryFilterChain filterChain) { + * System.out.println("Do something before query"); + * // process query or return some custom response + * QueryResponse response = filterChain.onQuery(originatingContext, query); + * System.out.println("Do something after query"); + * return response; + * } + * }}</pre> + * + * @see DataChannelSyncFilter + * @see org.apache.cayenne.configuration.server.ServerModule#contributeDomainQueryFilters(org.apache.cayenne.di.Binder) + * * @since 4.1 */ @FunctionalInterface public interface DataChannelQueryFilter { + /** + * @param originatingContext originating context of query + * @param query that is processed + * @param filterChain chain of query filters to invoke after this filter + * @return query response + */ QueryResponse onQuery(ObjectContext originatingContext, Query query, DataChannelQueryFilterChain filterChain); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilterChain.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilterChain.java b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilterChain.java index 322d9d2..4d1b4e4 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilterChain.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelQueryFilterChain.java @@ -22,6 +22,8 @@ package org.apache.cayenne; import org.apache.cayenne.query.Query; /** + * Interface for chain of query filters + * * @since 4.1 */ public interface DataChannelQueryFilterChain { http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilter.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilter.java b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilter.java index 96f1cdd..b37f8c4 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilter.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilter.java @@ -22,10 +22,44 @@ package org.apache.cayenne; import org.apache.cayenne.graph.GraphDiff; /** + * An interface of a filter that allows to intercept DataChannel sync operations. + * Sync filters allow to implement chains of custom processors around a DataChannel. + * <p> + * Example: <pre>{@code + * public class MySyncFilter implements DataChannelSyncFilter { + * public GraphDiff onSync(ObjectContext originatingContext, + * GraphDiff changes, + * int syncType, + * DataChannelSyncFilterChain filterChain) { + * System.out.println("Do something before sync"); + * // process changes or return some custom diff + * GraphDiff diff = filterChain.onSync(originatingContext, changes, syncType); + * System.out.println("Do something after sync"); + * return diff; + * } + * }}</pre> + * + * @see DataChannelQueryFilter + * @see org.apache.cayenne.configuration.server.ServerModule#contributeDomainSyncFilters(org.apache.cayenne.di.Binder) + * * @since 4.1 */ +@FunctionalInterface public interface DataChannelSyncFilter { + /** + * @param originatingContext originating context of changes + * @param changes diff that is being processed + * @param syncType type of sync; possible values: {@link DataChannel#FLUSH_NOCASCADE_SYNC}, + * {@link DataChannel#FLUSH_CASCADE_SYNC}, + * {@link DataChannel#ROLLBACK_CASCADE_SYNC} + * @param filterChain chain of sync filters to invoke after this filter + * @return final context diff + * + * @see DataChannel#FLUSH_NOCASCADE_SYNC + * @see DataChannel#FLUSH_CASCADE_SYNC + * @see DataChannel#ROLLBACK_CASCADE_SYNC + */ GraphDiff onSync( ObjectContext originatingContext, GraphDiff changes, http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java index cd5587c..6c7bf38 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/DataChannelSyncFilterChain.java @@ -20,6 +20,11 @@ package org.apache.cayenne; import org.apache.cayenne.graph.GraphDiff; +/** + * Interface for chain of sync filters + * + * @since 4.1 (it was present, but not used before 4.1) + */ public interface DataChannelSyncFilterChain { GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType); http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomain.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomain.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomain.java index ecd0938..a81c940 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomain.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomain.java @@ -44,13 +44,11 @@ import org.apache.cayenne.query.QueryChain; import org.apache.cayenne.tx.BaseTransaction; import org.apache.cayenne.tx.Transaction; import org.apache.cayenne.tx.TransactionManager; -import org.apache.cayenne.tx.TransactionalOperation; import org.apache.cayenne.util.ToStringBuilder; 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.concurrent.ConcurrentHashMap; @@ -731,7 +729,10 @@ public class DataDomain implements QueryEngine, DataChannel { * @since 4.1 */ public void addQueryFilter(DataChannelQueryFilter filter) { - addListener(filter); + // skip double listener registration, if filter already in sync filters list + if(!syncFilters.contains(filter)) { + addListener(filter); + } queryFilters.add(filter); } @@ -742,7 +743,10 @@ public class DataDomain implements QueryEngine, DataChannel { * @since 4.1 */ public void addSyncFilter(DataChannelSyncFilter filter) { - addListener(filter); + // skip double listener registration, if filter already in query filters list + if(!queryFilters.contains(filter)) { + addListener(filter); + } syncFilters.add(filter); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/b2d3b393/cayenne-server/src/test/java/org/apache/cayenne/access/DataDomainFiltersIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataDomainFiltersIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataDomainFiltersIT.java index c63e13e..d9aca80 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataDomainFiltersIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataDomainFiltersIT.java @@ -19,12 +19,16 @@ package org.apache.cayenne.access; import org.apache.cayenne.DataChannelQueryFilter; +import org.apache.cayenne.DataChannelQueryFilterChain; import org.apache.cayenne.DataChannelSyncFilter; +import org.apache.cayenne.DataChannelSyncFilterChain; import org.apache.cayenne.ObjectContext; import org.apache.cayenne.QueryResponse; +import org.apache.cayenne.annotation.PostPersist; 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.CayenneProjects; @@ -145,4 +149,45 @@ public class DataDomainFiltersIT extends ServerCase { assertSame(r2, response); } + + @Test + public void testSyncAndQueryFilter() { + ComplexFilter complexFilter = new ComplexFilter(); + DataDomain domain = runtime.getDataDomain(); + + domain.addQueryFilter(complexFilter); + domain.addSyncFilter(complexFilter); + + Artist a = context.newObject(Artist.class); + a.setArtistName("AAA"); + + // testing domain.onSync indirectly + context.commitChanges(); + + assertEquals(2, complexFilter.results.size()); + assertEquals("onSync", complexFilter.results.get(0)); + assertEquals("postPersist", complexFilter.results.get(1)); + } + + private static class ComplexFilter implements DataChannelQueryFilter, DataChannelSyncFilter { + + private List<String> results = new ArrayList<>(); + + @Override + public QueryResponse onQuery(ObjectContext originatingContext, Query query, DataChannelQueryFilterChain filterChain) { + results.add("onQuery"); + return filterChain.onQuery(originatingContext, query); + } + + @Override + public GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType, DataChannelSyncFilterChain filterChain) { + results.add("onSync"); + return filterChain.onSync(originatingContext, changes, syncType); + } + + @PostPersist + public void postPersist(Object object) { + results.add("postPersist"); + } + } }