You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/02/10 15:23:44 UTC
cayenne git commit: CAY-2225 New Cache Invalidation filter + module
builder to include it into cayenne runtime
Repository: cayenne
Updated Branches:
refs/heads/master 4e54f8e2e -> 871574bcc
CAY-2225 New Cache Invalidation filter + module builder to include it into cayenne runtime
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/871574bc
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/871574bc
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/871574bc
Branch: refs/heads/master
Commit: 871574bcc0d2778c5421a677959eaedb8e19c58b
Parents: 4e54f8e
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Feb 10 18:19:03 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Feb 10 18:19:03 2017 +0300
----------------------------------------------------------------------
.../lifecycle/cache/CacheGroupsHandler.java | 59 +++++++++
.../cache/CacheInvalidationFilter.java | 124 ++++++++++++-------
.../cache/CacheInvalidationModuleBuilder.java | 84 +++++++++++++
.../lifecycle/cache/InvalidationFunction.java | 36 ++++++
.../lifecycle/cache/InvalidationHandler.java | 35 ++++++
.../lifecycle/cache/CacheInvalidationIT.java | 77 ++++++++++++
.../lifecycle/unit/CacheInvalidationCase.java | 83 +++++++++++++
docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
8 files changed, 455 insertions(+), 44 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheGroupsHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheGroupsHandler.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheGroupsHandler.java
new file mode 100644
index 0000000..330a30c
--- /dev/null
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheGroupsHandler.java
@@ -0,0 +1,59 @@
+/*****************************************************************
+ * 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.lifecycle.cache;
+
+import java.util.Collection;
+
+import org.apache.cayenne.Persistent;
+
+import static java.util.Arrays.asList;
+
+/**
+ * @since 4.0
+ */
+public class CacheGroupsHandler implements InvalidationHandler {
+
+ /**
+ * Return invalidation function that returns values
+ * of {@link CacheGroups} annotations for the given type.
+ */
+ @Override
+ public InvalidationFunction canHandle(Class<? extends Persistent> type) {
+
+ CacheGroups a = type.getAnnotation(CacheGroups.class);
+ if (a == null) {
+ return null;
+ }
+
+ String[] groups = a.value();
+ if (groups.length == 0) {
+ return null;
+ }
+
+ final Collection<String> groupsList = asList(groups);
+ return new InvalidationFunction() {
+ @Override
+ public Collection<String> apply(Persistent persistent) {
+ return groupsList;
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationFilter.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationFilter.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationFilter.java
index aaf66d1..f18a668 100644
--- a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationFilter.java
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationFilter.java
@@ -16,71 +16,98 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
+
package org.apache.cayenne.lifecycle.cache;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataChannelFilter;
import org.apache.cayenne.DataChannelFilterChain;
import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.Persistent;
import org.apache.cayenne.QueryResponse;
-import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.annotation.PrePersist;
import org.apache.cayenne.annotation.PreRemove;
import org.apache.cayenne.annotation.PreUpdate;
import org.apache.cayenne.cache.QueryCache;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
import org.apache.cayenne.graph.GraphDiff;
import org.apache.cayenne.query.Query;
/**
- * A {@link DataChannelFilter} that invalidates cache groups defined for mapped entities
- * via {@link CacheGroups} annotations.
- *
+ * <p>
+ * A {@link DataChannelFilter} that invalidates cache groups.
+ * Use custom rules for invalidation provided via DI.
+ * </p>
+ * <p>
+ * Default rule is based on entities' {@link CacheGroups} annotation.
+ * </p>
+ * <p>
+ * To add default filter: <pre>
+ * ServerRuntime.builder("cayenne-project.xml")
+ * .addModule(CacheInvalidationModuleBuilder.builder().build());
+ * </pre>
+ * </p>
+ *
* @since 3.1
+ * @see InvalidationHandler
+ * @see CacheInvalidationModuleBuilder
*/
public class CacheInvalidationFilter implements DataChannelFilter {
- private final ThreadLocal<Set<String>> groups = new ThreadLocal<Set<String>>();
+ @Inject
+ private Provider<QueryCache> cacheProvider;
+
+ @Inject(CacheInvalidationModuleBuilder.INVALIDATION_HANDLERS_LIST)
+ private List<InvalidationHandler> handlers;
+
+ private final Map<Class<? extends Persistent>, InvalidationFunction> mappedHandlers;
+
+ private final InvalidationFunction skipHandler;
+
+ private final ThreadLocal<Set<String>> groups;
+
+ public CacheInvalidationFilter() {
+ mappedHandlers = new ConcurrentHashMap<>();
+ skipHandler = new InvalidationFunction() {
+ @Override
+ public Collection<String> apply(Persistent p) {
+ return Collections.emptyList();
+ }
+ };
+ groups = new ThreadLocal<>();
+ }
public void init(DataChannel channel) {
// noop
}
- public QueryResponse onQuery(
- ObjectContext originatingContext,
- Query query,
- DataChannelFilterChain filterChain) {
+ public QueryResponse onQuery(ObjectContext originatingContext, Query query, DataChannelFilterChain filterChain) {
return filterChain.onQuery(originatingContext, query);
}
- public GraphDiff onSync(
- ObjectContext originatingContext,
- GraphDiff changes,
- int syncType,
- DataChannelFilterChain filterChain) {
-
+ public GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes,
+ int syncType, DataChannelFilterChain filterChain) {
try {
GraphDiff result = filterChain.onSync(originatingContext, changes, syncType);
-
// no exceptions, flush...
-
Collection<String> groupSet = groups.get();
if (groupSet != null && !groupSet.isEmpty()) {
-
- // TODO: replace this with QueryCache injection once CAY-1445 is done
- QueryCache cache = ((DataContext) originatingContext).getQueryCache();
-
+ QueryCache cache = cacheProvider.get();
for (String group : groupSet) {
cache.removeGroup(group);
}
}
-
return result;
- }
- finally {
+ } finally {
groups.set(null);
}
}
@@ -88,31 +115,40 @@ public class CacheInvalidationFilter implements DataChannelFilter {
/**
* A callback method that records cache group to flush at the end of the commit.
*/
- @PrePersist(entityAnnotations = CacheGroups.class)
- @PreRemove(entityAnnotations = CacheGroups.class)
- @PreUpdate(entityAnnotations = CacheGroups.class)
+ @PrePersist
+ @PreRemove
+ @PreUpdate
protected void preCommit(Object object) {
-
- Set<String> groupSet = groups.get();
- if (groupSet == null) {
- groupSet = new HashSet<String>();
- groups.set(groupSet);
+ // TODO: for some reason we can't use Persistent as the argument type... (is it fixed in Cayenne 4.0.M4?)
+ Persistent p = (Persistent) object;
+
+ InvalidationFunction invalidationFunction = mappedHandlers.get(p.getClass());
+ if(invalidationFunction == null) {
+ invalidationFunction = skipHandler;
+ for (InvalidationHandler handler : handlers) {
+ InvalidationFunction function = handler.canHandle(p.getClass());
+ if (function != null) {
+ invalidationFunction = function;
+ break;
+ }
+ }
+ mappedHandlers.put(p.getClass(), invalidationFunction);
}
- addCacheGroups(groupSet, object);
+ Collection<String> objectGroups = invalidationFunction.apply(p);
+ if (!objectGroups.isEmpty()) {
+ getOrCreateTxGroups().addAll(objectGroups);
+ }
}
- /**
- * A method that builds a list of cache groups for a given object and adds them to the
- * invalidation group set. This implementation adds all groups defined via
- * {@link CacheGroups} annotation for a given class. Subclasses may override this
- * method to provide more fine-grained filtering of cache groups to invalidate, based
- * on the state of the object.
- */
- protected void addCacheGroups(Set<String> groupSet, Object object) {
- CacheGroups a = object.getClass().getAnnotation(CacheGroups.class);
- for (String group : a.value()) {
- groupSet.add(group);
+
+ protected Set<String> getOrCreateTxGroups() {
+ Set<String> txGroups = groups.get();
+ if (txGroups == null) {
+ txGroups = new HashSet<>();
+ groups.set(txGroups);
}
+
+ return txGroups;
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationModuleBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationModuleBuilder.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationModuleBuilder.java
new file mode 100644
index 0000000..d6ce504
--- /dev/null
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationModuleBuilder.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ * 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.lifecycle.cache;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.ListBuilder;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.tx.TransactionFilter;
+
+/**
+ * @since 4.0
+ */
+public class CacheInvalidationModuleBuilder {
+
+ public static final String INVALIDATION_HANDLERS_LIST = "cayenne.querycache.invalidation_handlers";
+
+ private Collection<Class<? extends InvalidationHandler>> handlerTypes;
+
+ private Collection<InvalidationHandler> handlerInstances;
+
+ public static CacheInvalidationModuleBuilder builder() {
+ return new CacheInvalidationModuleBuilder();
+ }
+
+ private static ListBuilder<InvalidationHandler> contributeInvalidationHandler(Binder binder) {
+ return binder.bindList(INVALIDATION_HANDLERS_LIST);
+ }
+
+ CacheInvalidationModuleBuilder() {
+ this.handlerTypes = new HashSet<>();
+ this.handlerInstances = new HashSet<>();
+ }
+
+ public CacheInvalidationModuleBuilder invalidationHandler(Class<? extends InvalidationHandler> handlerType) {
+ handlerTypes.add(handlerType);
+ return this;
+ }
+
+ public CacheInvalidationModuleBuilder invalidationHandler(InvalidationHandler handlerInstance) {
+ handlerInstances.add(handlerInstance);
+ return this;
+ }
+
+ public Module build() {
+ return new Module() {
+ @Override
+ public void configure(Binder binder) {
+ ListBuilder<InvalidationHandler> handlers = contributeInvalidationHandler(binder);
+
+ handlers.add(CacheGroupsHandler.class);
+ handlers.addAll(handlerInstances);
+
+ for(Class<? extends InvalidationHandler> handlerType : handlerTypes) {
+ handlers.add(handlerType);
+ }
+
+ // want the filter to be INSIDE transaction
+ binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST)
+ .add(CacheInvalidationFilter.class).before(TransactionFilter.class);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationFunction.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationFunction.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationFunction.java
new file mode 100644
index 0000000..8ae16db
--- /dev/null
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationFunction.java
@@ -0,0 +1,36 @@
+/*****************************************************************
+ * 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.lifecycle.cache;
+
+import java.util.Collection;
+
+import org.apache.cayenne.Persistent;
+
+/**
+ * @since 4.0
+ */
+public interface InvalidationFunction {
+
+ /**
+ * @return collection of cache groups to invalidate for given object
+ */
+ Collection<String> apply(Persistent persistent);
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationHandler.java b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationHandler.java
new file mode 100644
index 0000000..a667ead
--- /dev/null
+++ b/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/cache/InvalidationHandler.java
@@ -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.lifecycle.cache;
+
+import org.apache.cayenne.Persistent;
+
+/**
+ * A pluggable handler to invalidate cache groups on changes in certain objects.
+ * @since 4.0
+ */
+public interface InvalidationHandler {
+
+ /**
+ * @return invalidation function or null if there is nothing to invalidate
+ */
+ InvalidationFunction canHandle(Class<? extends Persistent> type);
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationIT.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationIT.java b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationIT.java
new file mode 100644
index 0000000..ff7a475
--- /dev/null
+++ b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/cache/CacheInvalidationIT.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ * 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.lifecycle.cache;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.lifecycle.db.E1;
+import org.apache.cayenne.lifecycle.unit.CacheInvalidationCase;
+import org.apache.cayenne.query.ObjectSelect;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.0
+ */
+public class CacheInvalidationIT extends CacheInvalidationCase {
+
+ @Test
+ public void testInvalidate_Custom() throws Exception {
+ ObjectContext context = runtime.newContext();
+
+ // no explicit cache group must still work - it lands inside default cache called 'cayenne.default.cache'
+ ObjectSelect<E1> g0 = ObjectSelect.query(E1.class).localCache();
+ g0.setName("q0");
+ ObjectSelect<E1> g1 = ObjectSelect.query(E1.class).localCache("g1");
+ g1.setName("q1");
+ ObjectSelect<E1> g2 = ObjectSelect.query(E1.class).localCache("g2");
+ g2.setName("q2");
+
+ assertEquals(0, g0.selectCount(context));
+ assertEquals(0, g1.selectCount(context));
+ assertEquals(0, g2.selectCount(context));
+
+ e1.insert(1).insert(2);
+
+ // inserted via SQL... query results are still cached...
+ assertEquals(0, g0.selectCount(context));
+ assertEquals(0, g1.selectCount(context));
+ assertEquals(0, g2.selectCount(context));
+
+
+ E1 e1 = context.newObject(E1.class);
+ context.commitChanges();
+ runtime.getDataDomain().getQueryCache().removeGroup("g1");
+
+ // inserted via Cayenne... "g1" should get auto refreshed...
+ assertEquals(0, g0.selectCount(context));
+ assertEquals(3, g1.selectCount(context));
+ assertEquals(0, g2.selectCount(context));
+
+ context.deleteObject(e1);
+ context.commitChanges();
+
+ // deleted via Cayenne... "g1" should get auto refreshed
+ assertEquals(0, g0.selectCount(context));
+ assertEquals(2, g1.selectCount(context));
+ assertEquals(0, g2.selectCount(context));
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/CacheInvalidationCase.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/CacheInvalidationCase.java b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/CacheInvalidationCase.java
new file mode 100644
index 0000000..2d17220
--- /dev/null
+++ b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/CacheInvalidationCase.java
@@ -0,0 +1,83 @@
+/*****************************************************************
+ * 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.lifecycle.unit;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.configuration.server.ServerRuntimeBuilder;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.lifecycle.cache.CacheGroups;
+import org.apache.cayenne.lifecycle.cache.CacheInvalidationModuleBuilder;
+import org.apache.cayenne.lifecycle.cache.InvalidationFunction;
+import org.apache.cayenne.lifecycle.cache.InvalidationHandler;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.junit.After;
+import org.junit.Before;
+
+public class CacheInvalidationCase {
+
+ protected ServerRuntime runtime;
+
+ protected TableHelper e1;
+
+ @Before
+ public void startCayenne() throws Exception {
+ this.runtime = configureCayenne().build();
+
+ DBHelper dbHelper = new DBHelper(runtime.getDataSource());
+
+ this.e1 = new TableHelper(dbHelper, "E1").setColumns("ID");
+ this.e1.deleteAll();
+ }
+
+ protected ServerRuntimeBuilder configureCayenne() {
+ Module cacheInvalidationModule = CacheInvalidationModuleBuilder
+ .builder()
+ .invalidationHandler(G1InvalidationHandler.class)
+ .build();
+
+ return ServerRuntime.builder()
+ .addModule(cacheInvalidationModule)
+ .addConfig("cayenne-lifecycle.xml");
+ }
+
+ @After
+ public void shutdownCayenne() {
+ if (runtime != null) {
+ runtime.shutdown();
+ }
+ }
+
+ public static class G1InvalidationHandler implements InvalidationHandler {
+ @Override
+ public InvalidationFunction canHandle(Class<? extends Persistent> type) {
+ return new InvalidationFunction() {
+ @Override
+ public Collection<String> apply(Persistent persistent) {
+ return Collections.singleton("g1");
+ }
+ };
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/871574bc/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index b94f929..7ea7ac7 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -29,6 +29,7 @@ CAY-2187 Support for the scalar and aggregate SQL functions in ObjectSelect API
CAY-2197 Update sqlite version and enable in-memory default config
CAY-2212 cdbimport cleanup and configuration schema refactoring
CAY-2223 JCacheQueryCache - a query cache provider to plug in JCache implementers
+CAY-2225 Extensible CacheInvalidationFilter logic
Bug Fixes: