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 <pmgheap....@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 <plehanov.a...@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>