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 14:32:57 UTC
cayenne git commit: CAY-2223 JCacheQueryCache - a query cache
provider to plug in JCache implementers
Repository: cayenne
Updated Branches:
refs/heads/master 00551aa28 -> 4365a8f94
CAY-2223 JCacheQueryCache - a query cache provider to plug in JCache implementers
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/4365a8f9
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/4365a8f9
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/4365a8f9
Branch: refs/heads/master
Commit: 4365a8f948ab1d74bd547153b203bc1d5b9dadbb
Parents: 00551aa
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Feb 10 17:32:46 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Feb 10 17:32:46 2017 +0300
----------------------------------------------------------------------
assembly/pom.xml | 6 +
.../resources/assemblies/assembly-generic.xml | 1 +
.../main/resources/assemblies/assembly-mac.xml | 1 +
.../resources/assemblies/assembly-windows.xml | 1 +
cayenne-jcache/pom.xml | 147 ++++++++++++++++
.../jcache/JCacheConfigurationFactory.java | 35 ++++
.../apache/cayenne/jcache/JCacheConstants.java | 33 ++++
.../JCacheDefaultConfigurationFactory.java | 56 ++++++
.../cayenne/jcache/JCacheEntryLoader.java | 54 ++++++
.../cayenne/jcache/JCacheManagerProvider.java | 76 ++++++++
.../org/apache/cayenne/jcache/JCacheModule.java | 49 ++++++
.../cayenne/jcache/JCacheModuleProvider.java | 47 +++++
.../apache/cayenne/jcache/JCacheQueryCache.java | 176 +++++++++++++++++++
.../org.apache.cayenne.di.spi.ModuleProvider | 1 +
.../cayenne/jcache/CayenneJCacheModuleIT.java | 85 +++++++++
.../jcache/CayenneJCacheModuleProviderTest.java | 31 ++++
.../jcache/unit/CacheServerRuntimeProvider.java | 51 ++++++
.../apache/cayenne/jcache/unit/JCacheCase.java | 59 +++++++
docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
pom.xml | 1 +
20 files changed, 911 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/assembly/pom.xml
----------------------------------------------------------------------
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 74d643f..4bfbaa9 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -97,6 +97,12 @@
</dependency>
<dependency>
+ <groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-jcache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.cayenne.modeler</groupId>
<artifactId>cayenne-modeler</artifactId>
<version>${project.version}</version>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/assembly/src/main/resources/assemblies/assembly-generic.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-generic.xml b/assembly/src/main/resources/assemblies/assembly-generic.xml
index e297a8a..679a2d2 100644
--- a/assembly/src/main/resources/assemblies/assembly-generic.xml
+++ b/assembly/src/main/resources/assemblies/assembly-generic.xml
@@ -85,6 +85,7 @@
<include>org.apache.cayenne:cayenne-ant</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
+ <include>org.apache.cayenne:cayenne-jcache</include>
</includes>
</dependencySet>
<dependencySet>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/assembly/src/main/resources/assemblies/assembly-mac.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-mac.xml b/assembly/src/main/resources/assemblies/assembly-mac.xml
index 8d94bb6..d65e9ba 100644
--- a/assembly/src/main/resources/assemblies/assembly-mac.xml
+++ b/assembly/src/main/resources/assemblies/assembly-mac.xml
@@ -85,6 +85,7 @@
<include>org.apache.cayenne:cayenne-ant</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
+ <include>org.apache.cayenne:cayenne-jcache</include>
</includes>
</dependencySet>
<dependencySet>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/assembly/src/main/resources/assemblies/assembly-windows.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/resources/assemblies/assembly-windows.xml b/assembly/src/main/resources/assemblies/assembly-windows.xml
index 2dd3781..660ba58 100644
--- a/assembly/src/main/resources/assemblies/assembly-windows.xml
+++ b/assembly/src/main/resources/assemblies/assembly-windows.xml
@@ -85,6 +85,7 @@
<include>org.apache.cayenne:cayenne-ant</include>
<include>org.apache.cayenne:cayenne-dbcp2</include>
<include>org.apache.cayenne:cayenne-java8</include>
+ <include>org.apache.cayenne:cayenne-jcache</include>
</includes>
</dependencySet>
<dependencySet>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-jcache/pom.xml b/cayenne-jcache/pom.xml
new file mode 100644
index 0000000..320d4e0
--- /dev/null
+++ b/cayenne-jcache/pom.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>cayenne-parent</artifactId>
+ <groupId>org.apache.cayenne</groupId>
+ <version>4.0.M5-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>cayenne-jcache</artifactId>
+ <name>cayenne-jcache: Cayenne JCache Integration</name>
+ <packaging>jar</packaging>
+
+ <properties>
+ <ehcache-version>3.2.0</ehcache-version>
+ <jcache-version>1.0.0</jcache-version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ <version>${ehcache-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.cache</groupId>
+ <artifactId>cache-api</artifactId>
+ <version>${jcache-version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+
+ <!-- Compile dependencies -->
+ <dependency>
+ <groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-server</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.cache</groupId>
+ <artifactId>cache-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- Test dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cayenne.build-tools</groupId>
+ <artifactId>cayenne-test-utilities</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cayenne</groupId>
+ <artifactId>cayenne-server</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- This ensures LICENSE and NOTICE inclusion in all jars -->
+ <plugin>
+ <artifactId>maven-remote-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>process</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <!--<configuration>
+ <suppressionsLocation>${project.basedir}/cayenne-checkstyle-suppression.xml</suppressionsLocation>
+ </configuration> -->
+ </plugin>
+ <plugin>
+ <artifactId>maven-pmd-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConfigurationFactory.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConfigurationFactory.java
new file mode 100644
index 0000000..e13c33a
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConfigurationFactory.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.jcache;
+
+import java.util.List;
+import javax.cache.configuration.Configuration;
+
+/**
+ * JCache configuration factory
+ *
+ * @see JCacheDefaultConfigurationFactory default implementation
+ * @since 4.0
+ */
+public interface JCacheConfigurationFactory {
+
+ Configuration<String, List> create(String cacheGroup);
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConstants.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConstants.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConstants.java
new file mode 100644
index 0000000..63a2ca6
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheConstants.java
@@ -0,0 +1,33 @@
+/*****************************************************************
+ * 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.jcache;
+
+/**
+ * @since 4.0
+ */
+public interface JCacheConstants {
+
+ /**
+ * Default JCache cache name. This will be the cache used for queries with no explicit cache groups.
+ */
+ String DEFAULT_CACHE_NAME = "cayenne.default.cache";
+
+ String JCACHE_PROVIDER_CONFIG = "cayenne.jcache.provider_config";
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheDefaultConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheDefaultConfigurationFactory.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheDefaultConfigurationFactory.java
new file mode 100644
index 0000000..fa1d611
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheDefaultConfigurationFactory.java
@@ -0,0 +1,56 @@
+/*****************************************************************
+ * 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.jcache;
+
+import java.util.List;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+
+/**
+ * <p>
+ * Default JCache configuration factory.
+ * </p>
+ * <p>
+ * Parameters:
+ * <ul>
+ * <li>store-by-reference</li>
+ * <li>expire in 10 minutes</li>
+ * </ul>
+ * </p>
+ *
+ * @since 4.0
+ */
+public class JCacheDefaultConfigurationFactory implements JCacheConfigurationFactory {
+
+ private final Configuration<String, List> configuration = new MutableConfiguration<String, List>()
+ .setTypes(String.class, List.class)
+ .setStoreByValue(false)
+ .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.TEN_MINUTES));
+
+ /**
+ * @param cacheGroup is unused by default configuration factory
+ * @return cache configuration
+ */
+ public Configuration<String, List> create(String cacheGroup) {
+ return configuration;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheEntryLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheEntryLoader.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheEntryLoader.java
new file mode 100644
index 0000000..1dbf3c1
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheEntryLoader.java
@@ -0,0 +1,54 @@
+/*****************************************************************
+ * 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.jcache;
+
+import java.util.List;
+import javax.cache.processor.EntryProcessor;
+import javax.cache.processor.EntryProcessorException;
+import javax.cache.processor.MutableEntry;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.cache.QueryCacheEntryFactory;
+
+/**
+ * @since 4.0
+ */
+public class JCacheEntryLoader implements EntryProcessor<String, List, List> {
+
+ private QueryCacheEntryFactory entryFactory;
+
+ public JCacheEntryLoader(QueryCacheEntryFactory entryFactory) {
+ this.entryFactory = entryFactory;
+ }
+
+ @Override
+ public List process(MutableEntry<String, List> entry, Object... arguments) throws EntryProcessorException {
+ if (!entry.exists()) {
+ List result = (List)entryFactory.createObject();
+ // sanity checking value
+ if (result == null) {
+ throw new CayenneRuntimeException("Null object created: " + entry.getKey());
+ }
+ entry.setValue(result);
+ }
+
+ return entry.getValue();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheManagerProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheManagerProvider.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheManagerProvider.java
new file mode 100644
index 0000000..cb69a7b
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheManagerProvider.java
@@ -0,0 +1,76 @@
+/*****************************************************************
+ * 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.jcache;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.cache.CacheException;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+
+/**
+ * @since 4.0
+ */
+public class JCacheManagerProvider implements Provider<CacheManager> {
+
+ @Inject
+ private RuntimeProperties properties;
+
+ @Override
+ public CacheManager get() throws DIRuntimeException {
+ CachingProvider provider;
+ try {
+ provider = Caching.getCachingProvider();
+ } catch (CacheException e) {
+ throw new RuntimeException("'cayenne-jcache' doesn't bundle any JCache providers. " +
+ "You must place a JCache 1.0 provider on classpath explicitly.", e);
+ }
+
+ CacheManager manager;
+ URI jcacheConfig = getConfig();
+
+ if(jcacheConfig == null) {
+ manager = provider.getCacheManager();
+ } else {
+ manager = provider.getCacheManager(jcacheConfig, null);
+ }
+
+ return manager;
+ }
+
+ private URI getConfig() {
+ String config = properties.get(JCacheConstants.JCACHE_PROVIDER_CONFIG);
+ if(config == null) {
+ return null;
+ } else {
+ try {
+ return new URI(config);
+ } catch (URISyntaxException ex) {
+ throw new RuntimeException("Wrong value for JCache provider config property", ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModule.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModule.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModule.java
new file mode 100644
index 0000000..081f56b
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModule.java
@@ -0,0 +1,49 @@
+/*****************************************************************
+ * 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.jcache;
+
+import javax.cache.CacheManager;
+
+import org.apache.cayenne.cache.QueryCache;
+import org.apache.cayenne.configuration.server.ServerModule;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.Module;
+
+/**
+ * <p>
+ * JCache Module
+ * </p>
+ *
+ * @since 4.0
+ */
+public class JCacheModule implements Module {
+
+ public static void contributeJCacheProviderConfig(Binder binder, String providerConfigURI) {
+ ServerModule.contributeProperties(binder).put(JCacheConstants.JCACHE_PROVIDER_CONFIG, providerConfigURI);
+ }
+
+ @Override
+ public void configure(Binder binder) {
+ binder.bind(CacheManager.class).toProvider(JCacheManagerProvider.class);
+ binder.bind(JCacheConfigurationFactory.class).to(JCacheDefaultConfigurationFactory.class);
+ binder.bind(QueryCache.class).to(JCacheQueryCache.class);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModuleProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModuleProvider.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModuleProvider.java
new file mode 100644
index 0000000..34f9cca
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheModuleProvider.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * 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.jcache;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.spi.ModuleProvider;
+
+/**
+ * @since 4.0
+ */
+public class JCacheModuleProvider implements ModuleProvider {
+
+ @Override
+ public Module module() {
+ return new JCacheModule();
+ }
+
+ @Override
+ public Class<? extends Module> moduleType() {
+ return JCacheModule.class;
+ }
+
+ @Override
+ public Collection<Class<? extends Module>> overrides() {
+ return Collections.emptyList();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheQueryCache.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheQueryCache.java b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheQueryCache.java
new file mode 100644
index 0000000..cc8c91f
--- /dev/null
+++ b/cayenne-jcache/src/main/java/org/apache/cayenne/jcache/JCacheQueryCache.java
@@ -0,0 +1,176 @@
+/*****************************************************************
+ * 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.jcache;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.cache.Cache;
+import javax.cache.CacheException;
+import javax.cache.CacheManager;
+
+import org.apache.cayenne.cache.QueryCache;
+import org.apache.cayenne.cache.QueryCacheEntryFactory;
+import org.apache.cayenne.di.BeforeScopeEnd;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.QueryMetadata;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @since 4.0
+ */
+public class JCacheQueryCache implements QueryCache {
+
+ private static final Log LOGGER = LogFactory.getLog(JCacheQueryCache.class);
+
+ @Inject
+ private CacheManager cacheManager;
+
+ @Inject
+ private JCacheConfigurationFactory configurationFactory;
+
+ private ConcurrentMap<String, Object> seenCacheNames = new ConcurrentHashMap<>();
+
+ @Override
+ public List get(QueryMetadata metadata) {
+ String key = Objects.requireNonNull(metadata.getCacheKey());
+ Cache<String, List> cache = createIfAbsent(metadata);
+
+ return cache.get(key);
+ }
+
+ @Override
+ public List get(QueryMetadata metadata, QueryCacheEntryFactory factory) {
+ String key = Objects.requireNonNull(metadata.getCacheKey());
+ Cache<String, List> cache = createIfAbsent(metadata);
+
+ List<?> result = cache.get(key);
+ return result != null
+ ? result
+ : cache.invoke(key, new JCacheEntryLoader(factory));
+ }
+
+ @Override
+ public void put(QueryMetadata metadata, List results) {
+ String key = Objects.requireNonNull(metadata.getCacheKey());
+ Cache<String, List> cache = createIfAbsent(metadata);
+
+ cache.put(key, results);
+ }
+
+ @Override
+ public void remove(String key) {
+ if (key != null) {
+ for (String cache : cacheManager.getCacheNames()) {
+ getCache(cache).remove(key);
+ }
+ }
+ }
+
+ @Override
+ public void removeGroup(String groupKey) {
+ Cache<String, List> cache = getCache(groupKey);
+ if (cache != null) {
+ cache.clear();
+ }
+ }
+
+ @Override
+ public void clear() {
+ for(String name : seenCacheNames.keySet()) {
+ getCache(name).clear();
+ }
+ }
+
+ /**
+ * Returns -1 to indicate that we can't calculate the size. JCache and EhCache can potentially have a complex topology
+ * that can not be meaningfully described by a single int. Use other means (like provider-specific JMX) to monitor cache.
+ *
+ * @deprecated since 4.0
+ * @return -1
+ */
+ @Override
+ @Deprecated
+ public int size() {
+ return -1;
+ }
+
+ protected Cache<String, List> createIfAbsent(QueryMetadata metadata) {
+ return createIfAbsent(cacheName(metadata));
+ }
+
+ protected Cache<String, List> createIfAbsent(String cacheName) {
+
+ Cache<String, List> cache = getCache(cacheName);
+ if (cache == null) {
+
+ try {
+ cache = cacheManager.createCache(cacheName, configurationFactory.create(cacheName));
+ } catch (CacheException e) {
+ // someone else just created this cache?
+ cache = getCache(cacheName);
+ if (cache == null) {
+ // giving up... the error was about something else...
+ throw e;
+ }
+ }
+
+ seenCacheNames.put(cacheName, 1);
+ }
+
+ return cache;
+ }
+
+ protected Cache<String, List> getCache(String name) {
+ return cacheManager.getCache(name, String.class, List.class);
+ }
+
+ protected String cacheName(QueryMetadata metadata) {
+
+ String[] cacheGroups = metadata.getCacheGroups();
+
+ if (cacheGroups != null && cacheGroups.length > 0) {
+
+ if (cacheGroups.length > 1) {
+ if (LOGGER.isWarnEnabled()) {
+ List<String> ignored = Arrays.asList(cacheGroups).subList(1, cacheGroups.length);
+ LOGGER.warn("multiple cache groups per key '" + metadata.getCacheKey() + "', using the first one: "
+ + cacheGroups[0] + ". Ignoring others: " + ignored);
+ }
+ }
+
+ return cacheGroups[0];
+ }
+
+ // no explicit cache groups
+ return JCacheConstants.DEFAULT_CACHE_NAME;
+ }
+
+ /**
+ * Shuts down CacheManager
+ */
+ @BeforeScopeEnd
+ public void shutdown() {
+ cacheManager.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider b/cayenne-jcache/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider
new file mode 100644
index 0000000..2fff139
--- /dev/null
+++ b/cayenne-jcache/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider
@@ -0,0 +1 @@
+org.apache.cayenne.jcache.JCacheModuleProvider
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleIT.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleIT.java b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleIT.java
new file mode 100644
index 0000000..156625a
--- /dev/null
+++ b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleIT.java
@@ -0,0 +1,85 @@
+/*****************************************************************
+ * 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.jcache;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.cache.NestedQueryCache;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.jcache.unit.JCacheCase;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class CayenneJCacheModuleIT extends JCacheCase {
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ ObjectContext context;
+
+ @Inject
+ ServerRuntime runtime;
+
+ private TableHelper tArtist;
+
+ @Before
+ public void setUpTableHelper() throws Exception {
+ tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+ tArtist.deleteAll();
+ }
+
+
+ @Test
+ public void testCachedQueries() throws Exception {
+ // make sure that we have JCacheQueryCache
+ assertEquals(JCacheQueryCache.class, ((NestedQueryCache)runtime.getDataDomain().getQueryCache()).getDelegate().getClass());
+
+ ObjectSelect<Artist> g1 = ObjectSelect.query(Artist.class).localCache("g1");
+ ObjectSelect<Artist> g2 = ObjectSelect.query(Artist.class).localCache("g2");
+
+ tArtist.insert(1, "artist1");
+ tArtist.insert(2, "artist2");
+ assertEquals(2, g1.select(context).size());
+
+ // we are still cached, must not see the new changes
+ tArtist.insert(3, "artist3");
+ tArtist.insert(4, "artist4");
+ assertEquals(2, g1.select(context).size());
+
+ // different cache group - must see the changes
+ assertEquals(4, g2.select(context).size());
+
+ // refresh the cache, so that "g1" could see the changes
+ runtime.getDataDomain().getQueryCache().removeGroup("g1");
+ assertEquals(4, g1.select(context).size());
+ assertEquals(4, g2.select(context).size());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleProviderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleProviderTest.java b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleProviderTest.java
new file mode 100644
index 0000000..10b9388
--- /dev/null
+++ b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/CayenneJCacheModuleProviderTest.java
@@ -0,0 +1,31 @@
+/*****************************************************************
+ * 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.jcache;
+
+import org.apache.cayenne.unit.util.ModuleProviderChecker;
+import org.junit.Test;
+
+public class CayenneJCacheModuleProviderTest {
+
+ @Test
+ public void testAutoLoadable() {
+ ModuleProviderChecker.testProviderPresent(JCacheModuleProvider.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/CacheServerRuntimeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/CacheServerRuntimeProvider.java b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/CacheServerRuntimeProvider.java
new file mode 100644
index 0000000..4595a28
--- /dev/null
+++ b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/CacheServerRuntimeProvider.java
@@ -0,0 +1,51 @@
+/*****************************************************************
+ * 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.jcache.unit;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.jcache.JCacheModule;
+import org.apache.cayenne.unit.UnitDbAdapter;
+import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
+import org.apache.cayenne.unit.di.server.ServerCaseProperties;
+import org.apache.cayenne.unit.di.server.ServerRuntimeProvider;
+
+public class CacheServerRuntimeProvider extends ServerRuntimeProvider {
+
+ public CacheServerRuntimeProvider(@Inject ServerCaseDataSourceFactory dataSourceFactory,
+ @Inject ServerCaseProperties properties,
+ @Inject Provider<DbAdapter> dbAdapterProvider,
+ @Inject UnitDbAdapter unitDbAdapter) {
+ super(dataSourceFactory, properties, dbAdapterProvider, unitDbAdapter);
+ }
+
+ @Override
+ protected Collection<? extends Module> getExtraModules() {
+ Collection<Module> modules = new ArrayList<>();
+ modules.addAll(super.getExtraModules());
+ modules.add(new JCacheModule());
+ return modules;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/JCacheCase.java
----------------------------------------------------------------------
diff --git a/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/JCacheCase.java b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/JCacheCase.java
new file mode 100644
index 0000000..d87ff26
--- /dev/null
+++ b/cayenne-jcache/src/test/java/org/apache/cayenne/jcache/unit/JCacheCase.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.jcache.unit;
+
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.DIBootstrap;
+import org.apache.cayenne.di.Injector;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.spi.DefaultScope;
+import org.apache.cayenne.unit.di.DICase;
+import org.apache.cayenne.unit.di.server.SchemaBuilder;
+import org.apache.cayenne.unit.di.server.ServerCaseModule;
+import org.junit.BeforeClass;
+
+/**
+ * @since 4.0
+ */
+public class JCacheCase extends DICase {
+
+ private static Injector injector;
+
+ @BeforeClass
+ static public void setupInjector() {
+ final DefaultScope testScope = new DefaultScope();
+ injector = DIBootstrap.createInjector(
+ new ServerCaseModule(testScope),
+ new Module() {
+ @Override
+ public void configure(Binder binder) {
+ binder.bind(ServerRuntime.class).toProvider(CacheServerRuntimeProvider.class).in(testScope);
+ }
+ }
+ );
+ injector.getInstance(SchemaBuilder.class).rebuildSchema();
+ }
+
+ @Override
+ protected Injector getUnitTestInjector() {
+ return injector;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/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 4d59c51..b94f929 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -28,6 +28,7 @@ CAY-2177 Sync auto generated state of PK between model and DB
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
Bug Fixes:
http://git-wip-us.apache.org/repos/asf/cayenne/blob/4365a8f9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0c492f4..ec57fe9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
<module>cayenne-crypto</module>
<module>cayenne-joda</module>
<module>cayenne-dbcp2</module>
+ <module>cayenne-jcache</module>
<module>itests</module>
<module>modeler</module>
<module>maven-plugins</module>