You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2021/02/19 10:24:10 UTC
[ignite-extensions] branch master updated: IGNITE-14146 Migrate
Spring Cache integration to ignite-extensions - Fixes #42.
This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git
The following commit(s) were added to refs/heads/master by this push:
new 8e742ce IGNITE-14146 Migrate Spring Cache integration to ignite-extensions - Fixes #42.
8e742ce is described below
commit 8e742cefaceea48874539db8bfa8ac00fce03b0f
Author: Mikhail Petrov <pm...@gmail.com>
AuthorDate: Fri Feb 19 13:21:08 2021 +0300
IGNITE-14146 Migrate Spring Cache integration to ignite-extensions - Fixes #42.
Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
modules/spring-cache-ext/README.txt | 40 +++
modules/spring-cache-ext/licenses/apache-2.0.txt | 202 +++++++++++
.../modules/core/src/test/config/log4j-test.xml | 97 +++++
.../modules/core/src/test/config/tests.properties | 22 ++
modules/spring-cache-ext/pom.xml | 85 +++++
.../apache/ignite/cache/spring/SpringCache.java | 172 +++++++++
.../ignite/cache/spring/SpringCacheManager.java | 389 ++++++++++++++++++++
.../apache/ignite/cache/spring/package-info.java | 23 ++
.../apache/ignite/TestInjectionLifecycleBean.java | 42 +++
.../spring/GridSpringCacheManagerAbstractTest.java | 398 +++++++++++++++++++++
.../GridSpringCacheManagerMultiJvmSelfTest.java | 131 +++++++
.../spring/GridSpringCacheManagerSelfTest.java | 64 ++++
.../GridSpringCacheManagerSpringBeanSelfTest.java | 46 +++
.../cache/spring/GridSpringCacheTestKey.java | 61 ++++
.../spring/GridSpringCacheTestKeyGenerator.java | 40 +++
.../cache/spring/GridSpringCacheTestService.java | 181 ++++++++++
.../spring/GridSpringDynamicCacheTestService.java | 98 +++++
.../SpringCacheManagerContextInjectionTest.java | 128 +++++++
.../ignite/cache/spring/SpringCacheTest.java | 184 ++++++++++
.../spring/spring-caching-ignite-spring-bean.xml | 90 +++++
.../apache/ignite/cache/spring/spring-caching.xml | 57 +++
.../apache/ignite/cache/spring/spring-caching1.xml | 56 +++
.../apache/ignite/cache/spring/spring-caching2.xml | 56 +++
.../org/apache/ignite/spring-injection-test.xml | 43 +++
.../testsuites/IgniteSpringCacheTestSuite.java | 40 +++
modules/spring-tx-ext/README.txt | 4 +-
parent/pom.xml | 5 +
pom.xml | 1 +
28 files changed, 2753 insertions(+), 2 deletions(-)
diff --git a/modules/spring-cache-ext/README.txt b/modules/spring-cache-ext/README.txt
new file mode 100644
index 0000000..85cb178
--- /dev/null
+++ b/modules/spring-cache-ext/README.txt
@@ -0,0 +1,40 @@
+Apache Ignite Spring Cache Module
+---------------------------
+
+Apache Ignite Spring Cache extension provides an integration with Spring Cache framework.
+
+Importing Spring Cache extension In Maven Project
+----------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add Spring Cache extension dependency like this (replace '${ignite-spring-cache-ext.version}' and '${ignite.version}' with actual version of Ignite Spring Cache extension and Ignite you are interested in, respectively):
+
+ <!-- Please note that for Ignite versions earlier than 2.11, the ignite-spring-cache-ext dependency must be added to classpath before ignite-spring, due to duplication of Spring Cache integration classes. If you are using Maven to manage dependencies, it just needs to place ignite-spring-cache-ext before ignite-spring dependency in your pom file. --!>
+
+<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">
+ ...
+ <dependencies>
+ ...
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-spring-cache-ext</artifactId>
+ <version>${ignite-spring-cache-ext.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-spring</artifactId>
+ <version>${ignite.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${ignite.version}</version>
+ </dependency>
+ ...
+ </dependencies>
+ ...
+</project>
diff --git a/modules/spring-cache-ext/licenses/apache-2.0.txt b/modules/spring-cache-ext/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/spring-cache-ext/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/modules/spring-cache-ext/modules/core/src/test/config/log4j-test.xml b/modules/spring-cache-ext/modules/core/src/test/config/log4j-test.xml
new file mode 100755
index 0000000..3061bd4
--- /dev/null
+++ b/modules/spring-cache-ext/modules/core/src/test/config/log4j-test.xml
@@ -0,0 +1,97 @@
+<?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.
+-->
+
+<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN"
+ "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
+<!--
+ Log4j configuration.
+-->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+ <!--
+ Logs System.out messages to console.
+ -->
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <!-- Log to STDOUT. -->
+ <param name="Target" value="System.out"/>
+
+ <!-- Log from DEBUG and higher. -->
+ <param name="Threshold" value="DEBUG"/>
+
+ <!-- The default pattern: Date Priority [Category] Message\n -->
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%d{ISO8601}][%-5p][%t][%c{1}] %m%n"/>
+ </layout>
+
+ <!-- Do not log beyond INFO level. -->
+ <filter class="org.apache.log4j.varia.LevelRangeFilter">
+ <param name="levelMin" value="DEBUG"/>
+ <param name="levelMax" value="INFO"/>
+ </filter>
+ </appender>
+
+ <!--
+ Logs all System.err messages to console.
+ -->
+ <appender name="CONSOLE_ERR" class="org.apache.log4j.ConsoleAppender">
+ <!-- Log to STDERR. -->
+ <param name="Target" value="System.err"/>
+
+ <!-- Log from WARN and higher. -->
+ <param name="Threshold" value="WARN"/>
+
+ <!-- The default pattern: Date Priority [Category] Message\n -->
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%d{ISO8601}][%-5p][%t][%c{1}] %m%n"/>
+ </layout>
+ </appender>
+
+ <!--
+ Logs all output to specified file.
+ -->
+ <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
+ <param name="Threshold" value="DEBUG"/>
+ <param name="File" value="ignite/work/log/ignite.log"/>
+ <param name="Append" value="true"/>
+ <param name="MaxFileSize" value="10MB"/>
+ <param name="MaxBackupIndex" value="10"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%d{ISO8601}][%-5p][%t][%c{1}] %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- Disable all open source debugging. -->
+ <category name="org">
+ <level value="INFO"/>
+ </category>
+
+ <category name="org.eclipse.jetty">
+ <level value="INFO"/>
+ </category>
+
+ <!-- Default settings. -->
+ <root>
+ <!-- Print at info by default. -->
+ <level value="INFO"/>
+
+ <!-- Append to file and console. -->
+ <appender-ref ref="FILE"/>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="CONSOLE_ERR"/>
+ </root>
+</log4j:configuration>
diff --git a/modules/spring-cache-ext/modules/core/src/test/config/tests.properties b/modules/spring-cache-ext/modules/core/src/test/config/tests.properties
new file mode 100644
index 0000000..0faf5b8
--- /dev/null
+++ b/modules/spring-cache-ext/modules/core/src/test/config/tests.properties
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# Local address to bind to.
+local.ip=127.0.0.1
+
+# TCP communication port
+comm.tcp.port=30010
diff --git a/modules/spring-cache-ext/pom.xml b/modules/spring-cache-ext/pom.xml
new file mode 100644
index 0000000..0b5a190
--- /dev/null
+++ b/modules/spring-cache-ext/pom.xml
@@ -0,0 +1,85 @@
+<?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.
+-->
+
+<!--
+ POM file.
+-->
+<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">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-extensions-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../parent</relativePath>
+ </parent>
+
+ <artifactId>ignite-spring-cache-ext</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <url>http://ignite.apache.org</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${ignite.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-spring</artifactId>
+ <version>${ignite.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.thoughtworks.xstream</groupId>
+ <artifactId>xstream</artifactId>
+ <version>${xstream.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-log4j</artifactId>
+ <version>${ignite.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${ignite.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/java</directory>
+ <excludes>
+ <exclude>**/*.java</exclude>
+ </excludes>
+ </testResource>
+ </testResources>
+ </build>
+</project>
diff --git a/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCache.java b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCache.java
new file mode 100644
index 0000000..9a8f2a8
--- /dev/null
+++ b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCache.java
@@ -0,0 +1,172 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.io.Serializable;
+import java.util.concurrent.Callable;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteLock;
+import org.springframework.cache.Cache;
+import org.springframework.cache.support.SimpleValueWrapper;
+
+/**
+ * Spring cache implementation.
+ */
+class SpringCache implements Cache {
+ /** */
+ private static final Object NULL = new NullValue();
+
+ /** */
+ private final IgniteCache<Object, Object> cache;
+
+ /** */
+ private final SpringCacheManager mgr;
+
+ /**
+ * @param cache Cache.
+ * @param mgr Manager
+ */
+ SpringCache(IgniteCache<Object, Object> cache, SpringCacheManager mgr) {
+ assert cache != null;
+
+ this.cache = cache;
+ this.mgr = mgr;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getName() {
+ return cache.getName();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object getNativeCache() {
+ return cache;
+ }
+
+ /** {@inheritDoc} */
+ @Override public ValueWrapper get(Object key) {
+ Object val = cache.get(key);
+
+ return val != null ? fromValue(val) : null;
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override public <T> T get(Object key, Class<T> type) {
+ Object val = cache.get(key);
+
+ if (NULL.equals(val))
+ val = null;
+
+ if (val != null && type != null && !type.isInstance(val))
+ throw new IllegalStateException("Cached value is not of required type [cacheName=" + cache.getName() +
+ ", key=" + key + ", val=" + val + ", requiredType=" + type + ']');
+
+ return (T)val;
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override public <T> T get(final Object key, final Callable<T> valLdr) {
+ Object val = cache.get(key);
+
+ if (val == null) {
+ IgniteLock lock = mgr.getSyncLock(cache.getName(), key);
+
+ lock.lock();
+
+ try {
+ val = cache.get(key);
+
+ if (val == null) {
+ try {
+ T retVal = valLdr.call();
+
+ val = wrapNull(retVal);
+
+ cache.put(key, val);
+ }
+ catch (Exception e) {
+ throw new ValueRetrievalException(key, valLdr, e);
+ }
+ }
+ }
+ finally {
+ lock.unlock();
+ }
+ }
+
+ return (T)unwrapNull(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void put(Object key, Object val) {
+ if (val == null)
+ cache.withSkipStore().put(key, NULL);
+ else
+ cache.put(key, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public ValueWrapper putIfAbsent(Object key, Object val) {
+ Object old;
+
+ if (val == null)
+ old = cache.withSkipStore().getAndPutIfAbsent(key, NULL);
+ else
+ old = cache.getAndPutIfAbsent(key, val);
+
+ return old != null ? fromValue(old) : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void evict(Object key) {
+ cache.remove(key);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void clear() {
+ cache.removeAll();
+ }
+
+ /**
+ * @param val Cache value.
+ * @return Wrapped value.
+ */
+ private static ValueWrapper fromValue(Object val) {
+ assert val != null;
+
+ return new SimpleValueWrapper(unwrapNull(val));
+ }
+
+ private static Object unwrapNull(Object val) {
+ return NULL.equals(val) ? null : val;
+ }
+
+ private <T> Object wrapNull(T val) {
+ return val == null ? NULL : val;
+ }
+
+ /** */
+ private static class NullValue implements Serializable {
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ return this == o || (o != null && getClass() == o.getClass());
+ }
+ }
+}
diff --git a/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCacheManager.java b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCacheManager.java
new file mode 100644
index 0000000..80f62d7
--- /dev/null
+++ b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/SpringCacheManager.java
@@ -0,0 +1,389 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteLock;
+import org.apache.ignite.IgniteSpring;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * Implementation of Spring cache abstraction based on Ignite cache.
+ * <h1 class="header">Overview</h1>
+ * Spring cache abstraction allows to enable caching for Java methods
+ * so that the result of a method execution is stored in some storage. If
+ * later the same method is called with the same set of parameters,
+ * the result will be retrieved from that storage instead of actually
+ * executing the method. For more information, refer to
+ * <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html">
+ * Spring Cache Abstraction documentation</a>.
+ * <h1 class="header">How To Enable Caching</h1>
+ * To enable caching based on Ignite cache in your Spring application,
+ * you will need to do the following:
+ * <ul>
+ * <li>
+ * Start an Ignite node with proper configuration in embedded mode
+ * (i.e., in the same JVM where the application is running). It can
+ * already have predefined caches, but it's not required - caches
+ * will be created automatically on first access if needed.
+ * </li>
+ * <li>
+ * Configure {@code SpringCacheManager} as a cache provider
+ * in the Spring application context.
+ * </li>
+ * </ul>
+ * {@code SpringCacheManager} can start a node itself on its startup
+ * based on provided Ignite configuration. You can provide path to a
+ * Spring configuration XML file, like below (path can be absolute or
+ * relative to {@code IGNITE_HOME}):
+ * <pre name="code" class="xml">
+ * <beans xmlns="http://www.springframework.org/schema/beans"
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ * xmlns:cache="http://www.springframework.org/schema/cache"
+ * xsi:schemaLocation="
+ * http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ * http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ * <-- Provide configuration file path. -->
+ * <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ * <property name="configurationPath" value="examples/config/spring-cache.xml"/>
+ * </bean>
+ *
+ * <-- Use annotation-driven caching configuration. -->
+ * <cache:annotation-driven/>
+ * </beans>
+ * </pre>
+ * Or you can provide a {@link IgniteConfiguration} bean, like below:
+ * <pre name="code" class="xml">
+ * <beans xmlns="http://www.springframework.org/schema/beans"
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ * xmlns:cache="http://www.springframework.org/schema/cache"
+ * xsi:schemaLocation="
+ * http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ * http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ * <-- Provide configuration bean. -->
+ * <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ * <property name="configuration">
+ * <bean id="gridCfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ * ...
+ * </bean>
+ * </property>
+ * </bean>
+ *
+ * <-- Use annotation-driven caching configuration. -->
+ * <cache:annotation-driven/>
+ * </beans>
+ * </pre>
+ * Note that providing both configuration path and configuration bean is illegal
+ * and results in {@link IllegalArgumentException}.
+ * <p>
+ * If you already have Ignite node running within your application,
+ * simply provide correct Ignite instance name, like below (if there is no Grid
+ * instance with such name, exception will be thrown):
+ * <pre name="code" class="xml">
+ * <beans xmlns="http://www.springframework.org/schema/beans"
+ * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ * xmlns:cache="http://www.springframework.org/schema/cache"
+ * xsi:schemaLocation="
+ * http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ * http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ * <-- Provide Ignite instance name. -->
+ * <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ * <property name="igniteInstanceName" value="myGrid"/>
+ * </bean>
+ *
+ * <-- Use annotation-driven caching configuration. -->
+ * <cache:annotation-driven/>
+ * </beans>
+ * </pre>
+ * This can be used, for example, when you are running your application
+ * in a J2EE Web container and use {@ignitelink org.apache.ignite.startup.servlet.ServletContextListenerStartup}
+ * for node startup.
+ * <p>
+ * If neither {@link #setConfigurationPath(String) configurationPath},
+ * {@link #setConfiguration(IgniteConfiguration) configuration}, nor
+ * {@link #setIgniteInstanceName(String) igniteInstanceName} are provided, cache manager
+ * will try to use default Grid instance (the one with the {@code null}
+ * name). If it doesn't exist, exception will be thrown.
+ * <h1>Starting Remote Nodes</h1>
+ * Keep in mind that the node started inside your application is an entry point
+ * to the whole topology it connects to. You can start as many remote standalone
+ * nodes as you need using {@code bin/ignite.{sh|bat}} scripts provided in
+ * Ignite distribution, and all these nodes will participate
+ * in caching the data.
+ */
+public class SpringCacheManager implements CacheManager, ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {
+ /** Default locks count. */
+ private static final int DEFAULT_LOCKS_COUNT = 512;
+
+ /** IgniteLock name prefix. */
+ private static final String SPRING_LOCK_NAME_PREFIX = "springSync";
+
+ /** Caches map. */
+ private final ConcurrentMap<String, SpringCache> caches = new ConcurrentHashMap<>();
+
+ /** Grid configuration file path. */
+ private String cfgPath;
+
+ /** Ignite configuration. */
+ private IgniteConfiguration cfg;
+
+ /** Ignite instance name. */
+ private String igniteInstanceName;
+
+ /** Count of IgniteLocks are used for sync get */
+ private int locksCnt = DEFAULT_LOCKS_COUNT;
+
+ /** Dynamic cache configuration template. */
+ private CacheConfiguration<Object, Object> dynamicCacheCfg;
+
+ /** Dynamic near cache configuration template. */
+ private NearCacheConfiguration<Object, Object> dynamicNearCacheCfg;
+
+ /** Ignite instance. */
+ private Ignite ignite;
+
+ /** Spring context. */
+ private ApplicationContext springCtx;
+
+ /** Locks for value loading to support sync option. */
+ private ConcurrentHashMap<Integer, IgniteLock> locks = new ConcurrentHashMap<>();
+
+ /** {@inheritDoc} */
+ @Override public void setApplicationContext(ApplicationContext ctx) {
+ this.springCtx = ctx;
+ }
+
+ /**
+ * Gets configuration file path.
+ *
+ * @return Grid configuration file path.
+ */
+ public String getConfigurationPath() {
+ return cfgPath;
+ }
+
+ /**
+ * Sets configuration file path.
+ *
+ * @param cfgPath Grid configuration file path.
+ */
+ public void setConfigurationPath(String cfgPath) {
+ this.cfgPath = cfgPath;
+ }
+
+ /**
+ * Gets configuration bean.
+ *
+ * @return Grid configuration bean.
+ */
+ public IgniteConfiguration getConfiguration() {
+ return cfg;
+ }
+
+ /**
+ * Sets configuration bean.
+ *
+ * @param cfg Grid configuration bean.
+ */
+ public void setConfiguration(IgniteConfiguration cfg) {
+ this.cfg = cfg;
+ }
+
+ /**
+ * Gets grid name.
+ *
+ * @return Grid name.
+ * @deprecated Use {@link #getIgniteInstanceName()}.
+ */
+ @Deprecated
+ public String getGridName() {
+ return getIgniteInstanceName();
+ }
+
+ /**
+ * Sets grid name.
+ *
+ * @param gridName Grid name.
+ * @deprecated Use {@link #setIgniteInstanceName(String)}.
+ */
+ @Deprecated
+ public void setGridName(String gridName) {
+ setIgniteInstanceName(gridName);
+ }
+
+ /**
+ * Gets Ignite instance name.
+ *
+ * @return Ignite instance name.
+ */
+ public String getIgniteInstanceName() {
+ return igniteInstanceName;
+ }
+
+ /**
+ * Sets Ignite instance name.
+ *
+ * @param igniteInstanceName Ignite instance name.
+ */
+ public void setIgniteInstanceName(String igniteInstanceName) {
+ this.igniteInstanceName = igniteInstanceName;
+ }
+
+ /**
+ * Gets locks count.
+ *
+ * @return locks count.
+ */
+ public int getLocksCount() {
+ return locksCnt;
+ }
+
+ /**
+ * @param locksCnt locks count.
+ */
+ public void setLocksCount(int locksCnt) {
+ this.locksCnt = locksCnt;
+ }
+
+ /**
+ * Gets dynamic cache configuration template.
+ *
+ * @return Dynamic cache configuration template.
+ */
+ public CacheConfiguration<Object, Object> getDynamicCacheConfiguration() {
+ return dynamicCacheCfg;
+ }
+
+ /**
+ * Sets dynamic cache configuration template.
+ *
+ * @param dynamicCacheCfg Dynamic cache configuration template.
+ */
+ public void setDynamicCacheConfiguration(CacheConfiguration<Object, Object> dynamicCacheCfg) {
+ this.dynamicCacheCfg = dynamicCacheCfg;
+ }
+
+ /**
+ * Gets dynamic near cache configuration template.
+ *
+ * @return Dynamic near cache configuration template.
+ */
+ public NearCacheConfiguration<Object, Object> getDynamicNearCacheConfiguration() {
+ return dynamicNearCacheCfg;
+ }
+
+ /**
+ * Sets dynamic cache configuration template.
+ *
+ * @param dynamicNearCacheCfg Dynamic cache configuration template.
+ */
+ public void setDynamicNearCacheConfiguration(NearCacheConfiguration<Object, Object> dynamicNearCacheCfg) {
+ this.dynamicNearCacheCfg = dynamicNearCacheCfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onApplicationEvent(ContextRefreshedEvent event) {
+ if (ignite == null) {
+
+ if (cfgPath != null && cfg != null) {
+ throw new IllegalArgumentException("Both 'configurationPath' and 'configuration' are " +
+ "provided. Set only one of these properties if you need to start a Ignite node inside of " +
+ "SpringCacheManager. If you already have a node running, omit both of them and set" +
+ "'igniteInstanceName' property.");
+ }
+
+ try {
+ if (cfgPath != null) {
+ ignite = IgniteSpring.start(cfgPath, springCtx);
+ }
+ else if (cfg != null)
+ ignite = IgniteSpring.start(cfg, springCtx);
+ else
+ ignite = Ignition.ignite(igniteInstanceName);
+ }
+ catch (IgniteCheckedException e) {
+ throw U.convertException(e);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public Cache getCache(String name) {
+ assert ignite != null;
+
+ SpringCache cache = caches.get(name);
+
+ if (cache == null) {
+ CacheConfiguration<Object, Object> cacheCfg = dynamicCacheCfg != null ?
+ new CacheConfiguration<>(dynamicCacheCfg) : new CacheConfiguration<>();
+
+ NearCacheConfiguration<Object, Object> nearCacheCfg = dynamicNearCacheCfg != null ?
+ new NearCacheConfiguration<>(dynamicNearCacheCfg) : null;
+
+ cacheCfg.setName(name);
+
+ cache = new SpringCache(nearCacheCfg != null ? ignite.getOrCreateCache(cacheCfg, nearCacheCfg) :
+ ignite.getOrCreateCache(cacheCfg), this);
+
+ SpringCache old = caches.putIfAbsent(name, cache);
+
+ if (old != null)
+ cache = old;
+ }
+
+ return cache;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<String> getCacheNames() {
+ assert ignite != null;
+
+ return new ArrayList<>(caches.keySet());
+ }
+
+ /**
+ * Provides {@link org.apache.ignite.IgniteLock} for specified cache name and key.
+ *
+ * @param name cache name
+ * @param key key
+ * @return {@link org.apache.ignite.IgniteLock}
+ */
+ IgniteLock getSyncLock(String name, Object key) {
+ int hash = Objects.hash(name, key);
+
+ final int idx = hash % getLocksCount();
+
+ return locks.computeIfAbsent(idx, i -> ignite.reentrantLock(SPRING_LOCK_NAME_PREFIX + idx, true, false, true));
+ }
+}
diff --git a/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/package-info.java b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/package-info.java
new file mode 100644
index 0000000..164c804
--- /dev/null
+++ b/modules/spring-cache-ext/src/main/java/org/apache/ignite/cache/spring/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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 description. -->
+ * Contains implementation of Spring cache abstraction and <code>@Cacheable</code> annotation.
+ */
+
+package org.apache.ignite.cache.spring;
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/TestInjectionLifecycleBean.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/TestInjectionLifecycleBean.java
new file mode 100644
index 0000000..2b8c932
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/TestInjectionLifecycleBean.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ignite;
+
+import org.apache.ignite.lifecycle.LifecycleBean;
+import org.apache.ignite.lifecycle.LifecycleEventType;
+import org.apache.ignite.resources.SpringApplicationContextResource;
+import org.springframework.context.ApplicationContext;
+
+import static org.junit.Assert.assertNotNull;
+
+/** Lifecycle bean for testing. */
+public class TestInjectionLifecycleBean implements LifecycleBean {
+ /** */
+ @SpringApplicationContextResource
+ private ApplicationContext appCtx;
+
+ /** Checks that context was injected. */
+ public void checkState() {
+ assertNotNull(appCtx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onLifecycleEvent(LifecycleEventType evt) {
+ checkState();
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerAbstractTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerAbstractTest.java
new file mode 100644
index 0000000..1041501
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerAbstractTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.ignite.cache.spring;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Spring cache test.
+ */
+public abstract class GridSpringCacheManagerAbstractTest extends GridCommonAbstractTest {
+ /** */
+ protected static final String CACHE_NAME = "testCache";
+
+ /** */
+ protected static final String DYNAMIC_CACHE_NAME = "dynamicCache";
+
+ /** */
+ private static final Object NULL;
+
+ /**
+ */
+ static {
+ try {
+ NULL = U.field(SpringCache.class, "NULL");
+ }
+ catch (IgniteCheckedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** */
+ protected GridSpringCacheTestService svc;
+
+ /** */
+ protected GridSpringDynamicCacheTestService dynamicSvc;
+
+ /** {@inheritDoc} */
+ @Override public String getTestIgniteInstanceName() {
+ return "testGrid";
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSimpleKey() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i, svc.simpleKey(i));
+ assertEquals("value" + i, svc.simpleKey(i));
+ }
+
+ assertEquals(3, svc.called());
+
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals("value" + i, c.get(i));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSimpleKeyNullValue() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertNull(svc.simpleKeyNullValue(i));
+ assertNull(svc.simpleKeyNullValue(i));
+ }
+
+ assertEquals(3, svc.called());
+
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals(NULL, c.get(i));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testComplexKey() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i + "suffix" + i, svc.complexKey(i, "suffix" + i));
+ assertEquals("value" + i + "suffix" + i, svc.complexKey(i, "suffix" + i));
+ }
+
+ assertEquals(3, svc.called());
+
+ IgniteCache<GridSpringCacheTestKey, String> c = grid().cache(CACHE_NAME);
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals("value" + i + "suffix" + i, c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testComplexKeyNullValue() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertNull(svc.complexKeyNullValue(i, "suffix" + i));
+ assertNull(svc.complexKeyNullValue(i, "suffix" + i));
+ }
+
+ assertEquals(3, svc.called());
+
+ IgniteCache<GridSpringCacheTestKey, String> c = grid().cache(CACHE_NAME);
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals(NULL, c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSimpleKeyPut() throws Exception {
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i + "odd", svc.simpleKeyPut(i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals("value" + i + "odd", c.get(i));
+
+ assertEquals("value" + i + "even", svc.simpleKeyPut(i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals("value" + i + "even", c.get(i));
+ }
+
+ assertEquals(6, svc.called());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSimpleKeyPutNullValue() throws Exception {
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++) {
+ assertNull(svc.simpleKeyPutNullValue(i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals(NULL, c.get(i));
+
+ assertNull(svc.simpleKeyPutNullValue(i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals(NULL, c.get(i));
+ }
+
+ assertEquals(6, svc.called());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testComplexKeyPut() throws Exception {
+ IgniteCache<GridSpringCacheTestKey, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i + "suffix" + i + "odd", svc.complexKeyPut(i, "suffix" + i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals("value" + i + "suffix" + i + "odd", c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+
+ assertEquals("value" + i + "suffix" + i + "even", svc.complexKeyPut(i, "suffix" + i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals("value" + i + "suffix" + i + "even", c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+ }
+
+ assertEquals(6, svc.called());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testComplexKeyPutNullValue() throws Exception {
+ IgniteCache<GridSpringCacheTestKey, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++) {
+ assertNull(svc.complexKeyPutNullValue(i, "suffix" + i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals(NULL, c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+
+ assertNull(svc.complexKeyPutNullValue(i, "suffix" + i));
+
+ assertEquals(i + 1, c.size());
+ assertEquals(NULL, c.get(new GridSpringCacheTestKey(i, "suffix" + i)));
+ }
+
+ assertEquals(6, svc.called());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSimpleKeyEvict() throws Exception {
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++)
+ c.put(i, "value" + i);
+
+ assertEquals(3, c.size());
+
+ assertEquals("value0", c.get(0));
+ assertEquals("value1", c.get(1));
+ assertEquals("value2", c.get(2));
+
+ svc.simpleKeyEvict(2);
+
+ assertEquals(2, c.size());
+
+ assertEquals("value0", c.get(0));
+ assertEquals("value1", c.get(1));
+ assertNull(c.get(2));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testComplexKeyEvict() throws Exception {
+ IgniteCache<GridSpringCacheTestKey, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++)
+ c.put(new GridSpringCacheTestKey(i, "suffix" + i), "value" + i);
+
+ assertEquals(3, c.size());
+
+ assertEquals("value0", c.get(new GridSpringCacheTestKey(0, "suffix" + 0)));
+ assertEquals("value1", c.get(new GridSpringCacheTestKey(1, "suffix" + 1)));
+ assertEquals("value2", c.get(new GridSpringCacheTestKey(2, "suffix" + 2)));
+
+ svc.complexKeyEvict(2, "suffix" + 2);
+
+ assertEquals(2, c.size());
+
+ assertEquals("value0", c.get(new GridSpringCacheTestKey(0, "suffix" + 0)));
+ assertEquals("value1", c.get(new GridSpringCacheTestKey(1, "suffix" + 1)));
+ assertNull(c.get(new GridSpringCacheTestKey(2, "suffix" + 2)));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testEvictAll() throws Exception {
+ IgniteCache<Integer, String> c = grid().cache(CACHE_NAME);
+
+ for (int i = 0; i < 3; i++)
+ c.put(i, "value" + i);
+
+ assertEquals(3, c.size());
+
+ assertEquals("value0", c.get(0));
+ assertEquals("value1", c.get(1));
+ assertEquals("value2", c.get(2));
+
+ svc.evictAll();
+
+ assertEquals(0, c.size());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testDynamicCache() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i, dynamicSvc.cacheable(i));
+ assertEquals("value" + i, dynamicSvc.cacheable(i));
+ }
+
+ assertEquals(3, dynamicSvc.called());
+
+ IgniteCache<Integer, String> c = grid().cache(DYNAMIC_CACHE_NAME);
+
+ // Check that correct config is used.
+ assertEquals(2, c.getConfiguration(CacheConfiguration.class).getBackups());
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals("value" + i, c.get(i));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testDynamicCachePut() throws Exception {
+ for (int i = 0; i < 3; i++) {
+ assertEquals("value" + i, dynamicSvc.cachePut(i));
+ assertEquals("value" + i, dynamicSvc.cachePut(i));
+ }
+
+ assertEquals(6, dynamicSvc.called());
+
+ IgniteCache<Integer, String> c = grid().cache(DYNAMIC_CACHE_NAME);
+
+ // Check that correct config is used.
+ assertEquals(2, c.getConfiguration(CacheConfiguration.class).getBackups());
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 3; i++)
+ assertEquals("value" + i, c.get(i));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testDynamicCacheEvict() throws Exception {
+ CacheConfiguration<Integer, String> cacheCfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
+
+ cacheCfg.setName(DYNAMIC_CACHE_NAME);
+
+ IgniteCache<Integer, String> c = grid().createCache(cacheCfg);
+
+ for (int i = 0; i < 3; i++)
+ c.put(i, "value" + i);
+
+ assertEquals(3, c.size());
+
+ for (int i = 0; i < 2; i++) {
+ dynamicSvc.cacheEvict(i);
+ dynamicSvc.cacheEvict(i);
+ }
+
+ assertEquals(4, dynamicSvc.called());
+
+ assertEquals(1, c.size());
+
+ assertEquals("value2", c.get(2));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testDynamicCacheEvictAll() throws Exception {
+ CacheConfiguration<Integer, String> cacheCfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
+
+ cacheCfg.setName(DYNAMIC_CACHE_NAME);
+
+ IgniteCache<Integer, String> c = grid().createCache(cacheCfg);
+
+ for (int i = 0; i < 3; i++)
+ c.put(i, "value" + i);
+
+ assertEquals(3, c.size());
+
+ dynamicSvc.cacheEvictAll();
+ dynamicSvc.cacheEvictAll();
+
+ assertEquals(2, dynamicSvc.called());
+
+ assertEquals(0, c.size());
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerMultiJvmSelfTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerMultiJvmSelfTest.java
new file mode 100644
index 0000000..2bc78ce
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerMultiJvmSelfTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.testframework.junits.multijvm.IgniteProcessProxy;
+import org.junit.Test;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Spring cache test in multi jvm environment.
+ */
+public class GridSpringCacheManagerMultiJvmSelfTest extends GridCommonAbstractTest {
+ /** {@inheritDoc} */
+ @Override protected boolean isMultiJvm() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getTestIgniteInstanceName(int idx) {
+ return getTestIgniteInstanceName() + idx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getTestIgniteInstanceName() {
+ return "testGrid";
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testSyncCache() throws Exception {
+ IgniteEx loc = startGrid(0);
+
+ final int threads = 4;
+ final int entries = 1000;
+ final int remoteNum = 2;
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ List<IgniteInternalFuture<Integer>> futures = new ArrayList<>(remoteNum);
+
+ for (int i = 0; i < remoteNum; i++) {
+ final int gridIdx = i + 1;
+
+ final IgniteEx remote = startGrid(gridIdx);
+
+ IgniteInternalFuture<Integer> calledCntFut = GridTestUtils.runAsync(new Callable<Integer>() {
+ @Override public Integer call() throws Exception {
+ latch.await();
+
+ return executeRemotely((IgniteProcessProxy)remote, new TestIgniteCallable<Integer>() {
+ @Override public Integer call(Ignite ignite) throws Exception {
+ BeanFactory factory =
+ new ClassPathXmlApplicationContext(
+ "org/apache/ignite/cache/spring/spring-caching" + gridIdx + ".xml");
+
+ final GridSpringDynamicCacheTestService dynamicSvc =
+ (GridSpringDynamicCacheTestService)factory.getBean("dynamicTestService");
+
+ final CyclicBarrier barrier = new CyclicBarrier(threads);
+
+ GridTestUtils.runMultiThreaded(
+ new Callable() {
+ @Override public Object call() throws Exception {
+ for (int i = 0; i < entries; i++) {
+ barrier.await();
+
+ assertEquals("value" + i, dynamicSvc.cacheableSync(i));
+ assertEquals("value" + i, dynamicSvc.cacheableSync(i));
+ }
+
+ return null;
+ }
+ },
+ threads,
+ "get-sync");
+
+ return dynamicSvc.called();
+ }
+ });
+
+ }
+ });
+
+ futures.add(calledCntFut);
+ }
+
+ latch.countDown();
+
+ int totalCalledCnt = 0;
+
+ for (IgniteInternalFuture<Integer> future : futures)
+ totalCalledCnt += future.get();
+
+ IgniteCache<Object, Object> cache = loc.cache("dynamicCache");
+
+ assertEquals(entries, cache.size());
+ assertEquals(entries, totalCalledCnt);
+
+ for (int i = 0; i < entries; i++)
+ assertEquals("value" + i, cache.get(i));
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSelfTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSelfTest.java
new file mode 100644
index 0000000..75c722a
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSelfTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.ignite.cache.spring;
+
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Spring cache test.
+ */
+public class GridSpringCacheManagerSelfTest extends GridSpringCacheManagerAbstractTest {
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ CacheConfiguration cache = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+ cache.setName(CACHE_NAME);
+
+ cfg.setCacheConfiguration(cache);
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ startGrid();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ BeanFactory factory = new ClassPathXmlApplicationContext("org/apache/ignite/cache/spring/spring-caching.xml");
+
+ svc = (GridSpringCacheTestService)factory.getBean("testService");
+ dynamicSvc = (GridSpringDynamicCacheTestService)factory.getBean("dynamicTestService");
+
+ svc.reset();
+ dynamicSvc.reset();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ grid().cache(CACHE_NAME).removeAll();
+
+ grid().destroyCache(DYNAMIC_CACHE_NAME);
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSpringBeanSelfTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSpringBeanSelfTest.java
new file mode 100644
index 0000000..8c5fc10
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheManagerSpringBeanSelfTest.java
@@ -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.ignite.cache.spring;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.context.support.GenericXmlApplicationContext;
+
+/**
+ * Spring cache test.
+ */
+public class GridSpringCacheManagerSpringBeanSelfTest extends GridSpringCacheManagerAbstractTest {
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ ApplicationContext appCtx = new ClassPathXmlApplicationContext("org/apache/ignite/cache/spring/spring-caching-ignite-spring-bean.xml");
+
+ // To produce multiple calls of ApplicationListener::onApplicationEvent
+ GenericXmlApplicationContext child = new GenericXmlApplicationContext();
+ child.setParent(appCtx);
+ child.refresh();
+
+ svc = (GridSpringCacheTestService)appCtx.getBean("testService");
+ dynamicSvc = (GridSpringDynamicCacheTestService)appCtx.getBean("dynamicTestService");
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids();
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKey.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKey.java
new file mode 100644
index 0000000..3f55112
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKey.java
@@ -0,0 +1,61 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.io.Serializable;
+
+/**
+ * Complex key.
+ */
+public class GridSpringCacheTestKey implements Serializable {
+ /** */
+ private final Integer p1;
+
+ /** */
+ private final String p2;
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ */
+ public GridSpringCacheTestKey(Integer p1, String p2) {
+ assert p1 != null;
+ assert p2 != null;
+
+ this.p1 = p1;
+ this.p2 = p2;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ GridSpringCacheTestKey key = (GridSpringCacheTestKey)o;
+
+ return p1.equals(key.p1) && p2.equals(key.p2);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return 31 * p1 + p2.hashCode();
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKeyGenerator.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKeyGenerator.java
new file mode 100644
index 0000000..7bab6cb
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestKeyGenerator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.lang.reflect.Method;
+import org.springframework.cache.interceptor.KeyGenerator;
+
+/**
+ * Key generator.
+ */
+public class GridSpringCacheTestKeyGenerator implements KeyGenerator {
+ /** {@inheritDoc} */
+ @Override public Object generate(Object target, Method mtd, Object... params) {
+ assert params != null;
+ assert params.length > 0;
+
+ if (params.length == 1)
+ return params[0];
+ else {
+ assert params.length == 2;
+
+ return new GridSpringCacheTestKey((Integer)params[0], (String)params[1]);
+ }
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestService.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestService.java
new file mode 100644
index 0000000..544997d
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringCacheTestService.java
@@ -0,0 +1,181 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+
+/**
+ * Test service.
+ */
+public class GridSpringCacheTestService {
+ /** */
+ private final AtomicInteger cnt = new AtomicInteger();
+
+ /**
+ * @return How many times service was called.
+ */
+ public int called() {
+ return cnt.get();
+ }
+
+ /**
+ * Resets service.
+ */
+ public void reset() {
+ cnt.set(0);
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @Cacheable("testCache")
+ public String simpleKey(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return "value" + key;
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @Cacheable("testCache")
+ public String simpleKeyNullValue(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return null;
+ }
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ * @return Value.
+ */
+ @Cacheable("testCache")
+ public String complexKey(Integer p1, String p2) {
+ assert p1 != null;
+ assert p2 != null;
+
+ cnt.incrementAndGet();
+
+ return "value" + p1 + p2;
+ }
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ * @return Value.
+ */
+ @Cacheable("testCache")
+ public String complexKeyNullValue(Integer p1, String p2) {
+ assert p1 != null;
+ assert p2 != null;
+
+ cnt.incrementAndGet();
+
+ return null;
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @CachePut("testCache")
+ public String simpleKeyPut(Integer key) {
+ assert key != null;
+
+ int cnt0 = cnt.incrementAndGet();
+
+ return "value" + key + (cnt0 % 2 == 0 ? "even" : "odd");
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @CachePut("testCache")
+ public String simpleKeyPutNullValue(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return null;
+ }
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ * @return Value.
+ */
+ @CachePut("testCache")
+ public String complexKeyPut(Integer p1, String p2) {
+ assert p1 != null;
+ assert p2 != null;
+
+ int cnt0 = cnt.incrementAndGet();
+
+ return "value" + p1 + p2 + (cnt0 % 2 == 0 ? "even" : "odd");
+ }
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ * @return Value.
+ */
+ @CachePut("testCache")
+ public String complexKeyPutNullValue(Integer p1, String p2) {
+ assert p1 != null;
+ assert p2 != null;
+
+ cnt.incrementAndGet();
+
+ return null;
+ }
+
+ /**
+ * @param key Key.
+ */
+ @CacheEvict("testCache")
+ public void simpleKeyEvict(Integer key) {
+ // No-op.
+ }
+
+ /**
+ * @param p1 Parameter 1.
+ * @param p2 Parameter 2.
+ */
+ @CacheEvict("testCache")
+ public void complexKeyEvict(Integer p1, String p2) {
+ // No-op.
+ }
+
+ /**
+ */
+ @CacheEvict(value = "testCache", allEntries = true)
+ public void evictAll() {
+ // No-op.
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringDynamicCacheTestService.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringDynamicCacheTestService.java
new file mode 100644
index 0000000..b15a9c0
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/GridSpringDynamicCacheTestService.java
@@ -0,0 +1,98 @@
+/*
+ * 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.ignite.cache.spring;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+
+/**
+ * Test service.
+ */
+public class GridSpringDynamicCacheTestService {
+ /** */
+ private final AtomicInteger cnt = new AtomicInteger();
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @Cacheable("dynamicCache")
+ public String cacheable(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return "value" + key;
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @Cacheable(value = "dynamicCache", sync = true)
+ public String cacheableSync(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return "value" + key;
+ }
+
+ /**
+ * @param key Key.
+ * @return Value.
+ */
+ @CachePut("dynamicCache")
+ public String cachePut(Integer key) {
+ assert key != null;
+
+ cnt.incrementAndGet();
+
+ return "value" + key;
+ }
+
+ /**
+ * @param key Key.
+ */
+ @CacheEvict("dynamicCache")
+ public void cacheEvict(Integer key) {
+ cnt.incrementAndGet();
+ }
+
+ /**
+ */
+ @CacheEvict(value = "dynamicCache", allEntries = true)
+ public void cacheEvictAll() {
+ cnt.incrementAndGet();
+ }
+
+ /**
+ * @return Calls count.
+ */
+ public int called() {
+ return cnt.get();
+ }
+
+ /**
+ */
+ public void reset() {
+ cnt.set(0);
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheManagerContextInjectionTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheManagerContextInjectionTest.java
new file mode 100644
index 0000000..d13afcd
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheManagerContextInjectionTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.ignite.cache.spring;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.TestInjectionLifecycleBean;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgnitionEx;
+import org.apache.ignite.lifecycle.LifecycleBean;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ */
+public class SpringCacheManagerContextInjectionTest extends GridCommonAbstractTest {
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testBeanInjectionUsingConfigPath() throws Exception {
+ new AnnotationConfigApplicationContext(TestPathConfiguration.class);
+
+ Ignite grid = IgnitionEx.grid("springInjectionTest");
+
+ IgniteConfiguration cfg = grid.configuration();
+
+ LifecycleBean[] beans = cfg.getLifecycleBeans();
+
+ assertEquals(2, beans.length);
+
+ TestInjectionLifecycleBean bean1 = (TestInjectionLifecycleBean)beans[0];
+ TestInjectionLifecycleBean bean2 = (TestInjectionLifecycleBean)beans[1];
+
+ bean1.checkState();
+ bean2.checkState();
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testBeanInjectionUsingConfiguration() throws Exception {
+ BeanFactory factory = new AnnotationConfigApplicationContext(TestCfgConfiguration.class);
+
+ TestInjectionLifecycleBean bean1 = (TestInjectionLifecycleBean)factory.getBean("bean1");
+ TestInjectionLifecycleBean bean2 = (TestInjectionLifecycleBean)factory.getBean("bean2");
+
+ bean1.checkState();
+ bean2.checkState();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids();
+
+ super.afterTest();
+ }
+
+ /** */
+ @SuppressWarnings("WeakerAccess")
+ @Configuration
+ static class TestPathConfiguration {
+ /** */
+ @Bean(name = "mgr")
+ public SpringCacheManager springCacheManager() {
+ SpringCacheManager mgr = new SpringCacheManager();
+
+ mgr.setConfigurationPath("org/apache/ignite/spring-injection-test.xml");
+
+ return mgr;
+ }
+ }
+
+ /** */
+ @SuppressWarnings("WeakerAccess")
+ @Configuration
+ static class TestCfgConfiguration {
+ /** */
+ @Bean(name = "mgr")
+ public SpringCacheManager springCacheManager() {
+ IgniteConfiguration cfg = new IgniteConfiguration();
+
+ cfg.setLocalHost("127.0.0.1");
+
+ cfg.setIgniteInstanceName("scmt");
+
+ cfg.setLifecycleBeans(bean1(), bean2());
+
+ SpringCacheManager mgr = new SpringCacheManager();
+
+ mgr.setConfiguration(cfg);
+
+ return mgr;
+ }
+
+ /** */
+ @Bean(name = "bean1")
+ LifecycleBean bean1() {
+ return new TestInjectionLifecycleBean();
+ }
+
+ /** */
+ @Bean(name = "bean2")
+ LifecycleBean bean2() {
+ return new TestInjectionLifecycleBean();
+ }
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheTest.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheTest.java
new file mode 100644
index 0000000..8710273
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/SpringCacheTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.ignite.cache.spring;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+/**
+ * Tests for {@link SpringCache}
+ */
+public class SpringCacheTest extends GridCommonAbstractTest {
+ /** */
+ private static Ignite ignite;
+
+ /** Wrapped cache. */
+ private IgniteCache nativeCache;
+
+ /** Working cache. */
+ private SpringCache springCache;
+
+ /** */
+ private String cacheName;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ ignite = startGrid();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ G.stop(true);
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ cacheName = String.valueOf(System.currentTimeMillis());
+ nativeCache = ignite.getOrCreateCache(cacheName);
+ springCache = new SpringCache(nativeCache, null);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ ignite.destroyCache(cacheName);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testGetName() throws Exception {
+ assertEquals(cacheName, springCache.getName());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testGetNativeCache() throws Exception {
+ assertEquals(nativeCache, springCache.getNativeCache());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testGetByKey() throws Exception {
+ String key = "key";
+ String value = "value";
+
+ springCache.put(key, value);
+ assertEquals(value, springCache.get(key).get());
+
+ assertNull(springCache.get("wrongKey"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testGetByKeyType() throws Exception {
+ String key = "key";
+ String value = "value";
+
+ springCache.put(key, value);
+ assertEquals(value, springCache.get(key, String.class));
+
+ try {
+ springCache.get(key, Integer.class);
+ fail("Missing exception");
+ }
+ catch (Exception e) {
+ assertTrue(e.getMessage().startsWith("Cached value is not of required type [cacheName=" + cacheName));
+ }
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testPut() throws Exception {
+ String key = "key";
+ assertNull(springCache.get(key));
+
+ String value = "value";
+ springCache.put(key, value);
+
+ assertEquals(value, springCache.get(key).get());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testPutIfAbsent() throws Exception {
+ String key = "key";
+ String expected = "value";
+
+ assertNull(springCache.putIfAbsent(key, expected));
+
+ assertEquals(expected, springCache.putIfAbsent(key, "wrongValue").get());
+
+ assertEquals(expected, springCache.get(key).get());
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testEvict() throws Exception {
+ String key = "key";
+ assertNull(springCache.get(key));
+
+ springCache.put(key, "value");
+ assertNotNull(springCache.get(key));
+
+ springCache.evict(key);
+ assertNull(springCache.get(key));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testClear() throws Exception {
+ String key;
+ springCache.put((key = "key1"), "value1");
+ assertNotNull(springCache.get(key));
+ springCache.put((key = "key2"), "value2");
+ assertNotNull(springCache.get(key));
+ springCache.put((key = "key3"), "value3");
+ assertNotNull(springCache.get(key));
+
+ springCache.clear();
+
+ assertNull(springCache.get("key1"));
+ assertNull(springCache.get("key2"));
+ assertNull(springCache.get("key3"));
+ }
+}
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching-ignite-spring-bean.xml b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching-ignite-spring-bean.xml
new file mode 100644
index 0000000..2671a5d
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching-ignite-spring-bean.xml
@@ -0,0 +1,90 @@
+<?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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:cache="http://www.springframework.org/schema/cache"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+
+ <bean id="mySpringBean" class="org.apache.ignite.IgniteSpringBean">
+ <property name="configuration">
+ <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ <property name="peerClassLoadingEnabled" value="true"/>
+ <property name="igniteInstanceName" value="testGrid"/>
+
+ <property name="cacheConfiguration">
+ <list>
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ <property name="name" value="testCache"/>
+ <property name="atomicityMode" value="TRANSACTIONAL"/>
+ </bean>
+ </list>
+ </property>
+
+ <property name="discoverySpi">
+ <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+ <property name="ipFinder">
+ <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+ <property name="addresses">
+ <list>
+ <value>127.0.0.1:47500..47509</value>
+ </list>
+ </property>
+ </bean>
+ </property>
+ </bean>
+ </property>
+ </bean>
+ </property>
+ </bean>
+
+ <!--
+ Test service with cacheable methods.
+ -->
+ <bean id="testService" class="org.apache.ignite.cache.spring.GridSpringCacheTestService"/>
+
+ <!--
+ Test service with cacheable methods (dynamic cache).
+ -->
+ <bean id="dynamicTestService" class="org.apache.ignite.cache.spring.GridSpringDynamicCacheTestService"/>
+
+ <!--
+ Cache manager.
+ -->
+ <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ <property name="igniteInstanceName" value="testGrid"/>
+ <property name="dynamicCacheConfiguration">
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ <property name="backups" value="2"/>
+ </bean>
+ </property>
+ </bean>
+
+ <!--
+ Key generator.
+ -->
+ <bean id="keyGenerator" class="org.apache.ignite.cache.spring.GridSpringCacheTestKeyGenerator"/>
+
+ <!--
+ Enable annotation-driver configuration for caching.
+ -->
+ <cache:annotation-driven key-generator="keyGenerator"/>
+</beans>
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching.xml b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching.xml
new file mode 100644
index 0000000..f232275
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:cache="http://www.springframework.org/schema/cache"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ <!--
+ Test service with cacheable methods.
+ -->
+ <bean id="testService" class="org.apache.ignite.cache.spring.GridSpringCacheTestService"/>
+
+ <!--
+ Test service with cacheable methods (dynamic cache).
+ -->
+ <bean id="dynamicTestService" class="org.apache.ignite.cache.spring.GridSpringDynamicCacheTestService"/>
+
+ <!--
+ Cache manager.
+ -->
+ <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ <property name="igniteInstanceName" value="testGrid"/>
+ <property name="dynamicCacheConfiguration">
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ <property name="backups" value="2"/>
+ </bean>
+ </property>
+ </bean>
+
+ <!--
+ Key generator.
+ -->
+ <bean id="keyGenerator" class="org.apache.ignite.cache.spring.GridSpringCacheTestKeyGenerator"/>
+
+ <!--
+ Enable annotation-driver configuration for caching.
+ -->
+ <cache:annotation-driven key-generator="keyGenerator"/>
+</beans>
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching1.xml b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching1.xml
new file mode 100644
index 0000000..679fd97
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching1.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:cache="http://www.springframework.org/schema/cache"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ <!--
+ Test service with cacheable methods.
+ -->
+ <bean id="testService" class="org.apache.ignite.cache.spring.GridSpringCacheTestService"/>
+
+ <!--
+ Test service with cacheable methods (dynamic cache).
+ -->
+ <bean id="dynamicTestService" class="org.apache.ignite.cache.spring.GridSpringDynamicCacheTestService"/>
+
+ <!--
+ Cache manager.
+ -->
+ <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ <property name="igniteInstanceName" value="testGrid1"/>
+ <property name="dynamicCacheConfiguration">
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ </bean>
+ </property>
+ </bean>
+
+ <!--
+ Key generator.
+ -->
+ <bean id="keyGenerator" class="org.apache.ignite.cache.spring.GridSpringCacheTestKeyGenerator"/>
+
+ <!--
+ Enable annotation-driver configuration for caching.
+ -->
+ <cache:annotation-driven key-generator="keyGenerator"/>
+</beans>
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching2.xml b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching2.xml
new file mode 100644
index 0000000..6a9e25a
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/cache/spring/spring-caching2.xml
@@ -0,0 +1,56 @@
+<?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.
+ -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:cache="http://www.springframework.org/schema/cache"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
+ <!--
+ Test service with cacheable methods.
+ -->
+ <bean id="testService" class="org.apache.ignite.cache.spring.GridSpringCacheTestService"/>
+
+ <!--
+ Test service with cacheable methods (dynamic cache).
+ -->
+ <bean id="dynamicTestService" class="org.apache.ignite.cache.spring.GridSpringDynamicCacheTestService"/>
+
+ <!--
+ Cache manager.
+ -->
+ <bean id="cacheManager" class="org.apache.ignite.cache.spring.SpringCacheManager">
+ <property name="igniteInstanceName" value="testGrid2"/>
+ <property name="dynamicCacheConfiguration">
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ </bean>
+ </property>
+ </bean>
+
+ <!--
+ Key generator.
+ -->
+ <bean id="keyGenerator" class="org.apache.ignite.cache.spring.GridSpringCacheTestKeyGenerator"/>
+
+ <!--
+ Enable annotation-driver configuration for caching.
+ -->
+ <cache:annotation-driven key-generator="keyGenerator"/>
+</beans>
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/spring-injection-test.xml b/modules/spring-cache-ext/src/test/java/org/apache/ignite/spring-injection-test.xml
new file mode 100644
index 0000000..14072ff
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/spring-injection-test.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<!--
+ Ignite Spring configuration file to startup grid cache.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util.xsd">
+ <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ <property name="lifecycleBeans">
+ <array>
+ <bean id="bean1" class="org.apache.ignite.TestInjectionLifecycleBean"/>
+ <bean id="bean2" class="org.apache.ignite.TestInjectionLifecycleBean"/>
+ </array>
+ </property>
+
+ <property name="localHost" value="127.0.0.1"/>
+
+ <property name="igniteInstanceName" value="springInjectionTest"/>
+ </bean>
+</beans>
diff --git a/modules/spring-cache-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringCacheTestSuite.java b/modules/spring-cache-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringCacheTestSuite.java
new file mode 100644
index 0000000..6d7a797
--- /dev/null
+++ b/modules/spring-cache-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringCacheTestSuite.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ignite.testsuites;
+
+import org.apache.ignite.cache.spring.GridSpringCacheManagerMultiJvmSelfTest;
+import org.apache.ignite.cache.spring.GridSpringCacheManagerSelfTest;
+import org.apache.ignite.cache.spring.GridSpringCacheManagerSpringBeanSelfTest;
+import org.apache.ignite.cache.spring.SpringCacheManagerContextInjectionTest;
+import org.apache.ignite.cache.spring.SpringCacheTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Ignite Spring Cache tests.
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ GridSpringCacheManagerSelfTest.class,
+ GridSpringCacheManagerSpringBeanSelfTest.class,
+ SpringCacheManagerContextInjectionTest.class,
+ SpringCacheTest.class,
+ GridSpringCacheManagerMultiJvmSelfTest.class
+})
+public class IgniteSpringCacheTestSuite {
+}
diff --git a/modules/spring-tx-ext/README.txt b/modules/spring-tx-ext/README.txt
index 5c1e72f..9375526 100644
--- a/modules/spring-tx-ext/README.txt
+++ b/modules/spring-tx-ext/README.txt
@@ -10,7 +10,7 @@ There are two implementations of Apache Ignite Spring Transactions Manager - org
Importing Spring Transactions extension In Maven Project
----------------------------------------
-If you are using Maven to manage dependencies of your project, you can add Spring Transactions extension dependency like this (replace '${ignite-spring-tx-ext.version}', '${ignite-spring.version}' and '${ignite.version}' with actual version of Ignite Spring Transactions extension, Spring Transactions and Ignite you are interested in, respectively):
+If you are using Maven to manage dependencies of your project, you can add Spring Transactions extension dependency like this (replace '${ignite-spring-tx-ext.version}', '${spring.version}' and '${ignite.version}' with actual version of Ignite Spring Transactions extension, Spring Transactions and Ignite you are interested in, respectively):
<!-- Please note that for Ignite versions earlier than 2.11, the ignite-spring-tx-ext dependency must be added to classpath before ignite-spring, due to duplication of Spring Transactions integration classes. If you are using Maven to manage dependencies, it just needs to place ignite-spring-tx-ext before ignite-spring dependency in your pom file. --!>
@@ -25,7 +25,7 @@ If you are using Maven to manage dependencies of your project, you can add Sprin
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-spring-tx-ext</artifactId>
- <version>${ignite-spring-transactions.version}</version>
+ <version>${ignite-spring-tx-ext.version}</version>
</dependency>
<dependency>
diff --git a/parent/pom.xml b/parent/pom.xml
index 7492556..785559e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -145,6 +145,7 @@
<zstd.version>1.3.7-2</zstd.version>
<opencensus.version>0.22.0</opencensus.version>
<surefire.version>3.0.0-M4</surefire.version>
+ <xstream.version>1.4.8</xstream.version>
<!-- Maven plugins versions -->
<maven.javadoc.plugin.version>2.10.4</maven.javadoc.plugin.version>
@@ -372,6 +373,10 @@
<title>Spring Transactions Integration</title>
<packages>org.apache.ignite.transactions.spring*</packages>
</group>
+ <group>
+ <title>Spring Cache Integration</title>
+ <packages>org.apache.ignite.cache.spring*</packages>
+ </group>
</groups>
<bottom>
<![CDATA[
diff --git a/pom.xml b/pom.xml
index 4985347..8682549 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
<module>modules/spring-data-commons</module>
<module>modules/performance-statistics-ext</module>
<module>modules/spring-tx-ext</module>
+ <module>modules/spring-cache-ext</module>
</modules>
<profiles>