IGNITE-13722 Adds correct closing of Spring Data Ignite resources - Fixes #31.
Signed-off-by: Aleksey Plekhanov <plehanov.alex@gmail.com>
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
index 354e35b..de8cf0b 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -18,15 +18,28 @@
import java.util.Collection;
import java.util.Collections;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.apache.ignite.springdata20.repository.support.IgniteProxyFactory;
import org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
+
+import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;
/**
* Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
*/
public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+ /** Name of the auto-registered Ignite proxy factory bean. */
+ private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
+ /** Name of the auto-registered Ignite proxy bean prototype. */
+ private static final String IGNITE_PROXY_BEAN_NAME = "igniteProxy";
+
/** {@inheritDoc} */
@Override public String getModuleName() {
return "Apache Ignite";
@@ -46,4 +59,22 @@
@Override protected Collection<Class<?>> getIdentifyingTypes() {
return Collections.singleton(IgniteRepository.class);
}
+
+ /** {@inheritDoc} */
+ @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+ registerIfNotAlreadyRegistered(
+ BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+ registry,
+ IGNITE_PROXY_FACTORY_BEAN_NAME,
+ cfg);
+
+ registerIfNotAlreadyRegistered(
+ BeanDefinitionBuilder.genericBeanDefinition(IgniteProxy.class)
+ .setScope(SCOPE_PROTOTYPE)
+ .setFactoryMethodOnBean("igniteProxy", IGNITE_PROXY_FACTORY_BEAN_NAME)
+ .getBeanDefinition(),
+ registry,
+ IGNITE_PROXY_BEAN_NAME,
+ cfg);
+ }
}
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..d571cc2
--- /dev/null
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,140 @@
+/*
+ * 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.springdata20.repository.support;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.expression.StandardBeanExpressionResolver;
+
+import static org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactory.getRepositoryConfiguration;
+
+/**
+ * Represents factory for obtaining instances of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory implements ApplicationContextAware, DisposableBean {
+ /** Spring application expression resolver. */
+ private final BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
+
+ /** Repositories associated with Ignite proxy. */
+ private final Map<Class<?>, IgniteProxy> igniteProxies = new ConcurrentHashMap<>();
+
+ /** Spring application context. */
+ private ApplicationContext ctx;
+
+ /** Spring application bean expression context. */
+ private BeanExpressionContext beanExpressionCtx;
+
+ /**
+ * @param repoInterface The repository interface class for which {@link IgniteProxy} will be created.
+ * @return {@link IgniteProxy} instance.
+ */
+ public IgniteProxy igniteProxy(Class<?> repoInterface) {
+ return igniteProxies.computeIfAbsent(repoInterface, k -> createIgniteProxy(repoInterface));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+ this.ctx = ctx;
+
+ beanExpressionCtx = new BeanExpressionContext(
+ new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+ null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void destroy() throws Exception {
+ Set<IgniteProxy> proxies = new HashSet<>(igniteProxies.values());
+
+ Exception destroyE = null;
+
+ for (IgniteProxy proxy : proxies) {
+ if (proxy instanceof AutoCloseable) {
+ try {
+ ((AutoCloseable)proxy).close();
+ }
+ catch (Exception e) {
+ if (destroyE == null)
+ destroyE = e;
+ else
+ destroyE.addSuppressed(e);
+ }
+ }
+ }
+
+ if (destroyE != null)
+ throw destroyE;
+ }
+
+ /**
+ * Creates {@link IgniteProxy} to be used for providing access to the Ignite cluster for specified repository.
+ *
+ * @param repoInterface {@link Class} instance of the repository interface.
+ * @return Instance of {@link IgniteProxy} associated with specified repository.
+ *
+ * @see RepositoryConfig
+ */
+ private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
+ RepositoryConfig repoCfg = getRepositoryConfiguration(repoInterface);
+
+ Object connCfg;
+
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteInstance()));
+ }
+ catch (BeansException ex) {
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteCfg()));
+ }
+ catch (BeansException ex2) {
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class);
+ }
+ catch (BeansException ex3) {
+ throw new IllegalArgumentException("Invalid configuration for repository " +
+ repoInterface.getName() + ". No beans were found that provide connection configuration to the" +
+ " Ignite cluster. Check \"igniteInstance\", \"igniteCfg\", \"igniteSpringCfgPath\" parameters" +
+ " of " + RepositoryConfig.class.getName() + " repository annotation.");
+ }
+ }
+ }
+
+ return IgniteProxy.of(connCfg);
+ }
+
+ /**
+ * Evaluates the SpEL expression.
+ *
+ * @param spelExpression SpEL expression
+ * @return The result of evaluation of the SpEL expression.
+ */
+ private String evaluateExpression(String spelExpression) {
+ return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
+ }
+}
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
index dacb3e4..2096277 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactory.java
@@ -16,27 +16,15 @@
*/
package org.apache.ignite.springdata20.repository.support;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata20.repository.IgniteRepository;
import org.apache.ignite.springdata20.repository.config.DynamicQueryConfig;
import org.apache.ignite.springdata20.repository.config.Query;
import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
import org.apache.ignite.springdata20.repository.query.IgniteQuery;
import org.apache.ignite.springdata20.repository.query.IgniteQueryGenerator;
import org.apache.ignite.springdata20.repository.query.IgniteRepositoryQuery;
-import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
@@ -62,85 +50,44 @@
* @author Manuel Núñez (manuel.nunez@hawkore.com)
*/
public class IgniteRepositoryFactory extends RepositoryFactorySupport {
- /** Spring application context */
- private final ApplicationContext ctx;
-
- /** Spring application bean factory */
- private final DefaultListableBeanFactory beanFactory;
-
/** Spring application expression resolver */
private final StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
/** Spring application bean expression context */
private final BeanExpressionContext beanExpressionContext;
- /** Mapping of a repository to a cache. */
- private final Map<Class<?>, String> repoToCache = new HashMap<>();
+ /** Ignite cache proxy instance associated with the current repository. */
+ private final IgniteCacheProxy<?, ?> cache;
- /** Mapping of a repository to a ignite instance. */
- private final Map<Class<?>, IgniteProxy> repoToIgnite = new HashMap<>();
+ /** Ignite proxy instance associated with the current repository. */
+ private final IgniteProxy ignite;
/**
- * Creates the factory with initialized {@link Ignite} instance.
- *
- * @param ctx the ctx
+ * @param ctx Spring Application context.
+ * @param repoInterface Repository interface.
*/
- public IgniteRepositoryFactory(ApplicationContext ctx) {
- this.ctx = ctx;
+ public IgniteRepositoryFactory(ApplicationContext ctx, Class<?> repoInterface) {
+ ignite = ctx.getBean(IgniteProxy.class, repoInterface);
- beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+ beanExpressionContext = new BeanExpressionContext(
+ new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+ null);
- beanExpressionContext = new BeanExpressionContext(beanFactory, null);
- }
+ RepositoryConfig cfg = getRepositoryConfiguration(repoInterface);
- /** */
- private IgniteProxy igniteForRepoConfig(RepositoryConfig config) {
- try {
- Object igniteInstanceBean = ctx.getBean(evaluateExpression(config.igniteInstance()));
+ String cacheName = evaluateExpression(cfg.cacheName());
- if (igniteInstanceBean instanceof Ignite)
- return new IgniteProxyImpl((Ignite)igniteInstanceBean);
- else if (igniteInstanceBean instanceof IgniteClient)
- return new IgniteClientProxy((IgniteClient)igniteInstanceBean);
+ Assert.hasText(cacheName, "Invalid configuration for repository " + repoInterface.getName() +
+ ". Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+ " annotation to map this repository to the underlying cache.");
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
- " \"igniteInstance\" property of repository configuration must be one of the following types: " +
- Ignite.class.getName() + ", " + IgniteClient.class.getName());
- }
- catch (BeansException ex) {
- try {
- Object igniteCfgBean = ctx.getBean(evaluateExpression(config.igniteCfg()));
+ cache = cfg.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
- if (igniteCfgBean instanceof IgniteConfiguration) {
- try {
- // first try to attach to existing ignite instance
- return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)igniteCfgBean).getIgniteInstanceName()));
- }
- catch (Exception ignored) {
- // nop
- }
- return new IgniteProxyImpl(Ignition.start((IgniteConfiguration)igniteCfgBean));
- }
- else if (igniteCfgBean instanceof ClientConfiguration)
- return new IgniteClientProxy(Ignition.startClient((ClientConfiguration)igniteCfgBean));
-
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
- " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
- IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
-
- }
- catch (BeansException ex2) {
- try {
- String igniteSpringCfgPath = evaluateExpression(config.igniteSpringCfgPath());
- String path = (String)ctx.getBean(igniteSpringCfgPath);
- return new IgniteProxyImpl(Ignition.start(path));
- }
- catch (BeansException ex3) {
- throw new IgniteException("Failed to initialize Ignite repository factory. No beans required for" +
- " repository configuration were found. Check \"igniteInstance\", \"igniteCfg\"," +
- " \"igniteSpringCfgPath\" parameters of " + RepositoryConfig.class.getName() + "class.");
- }
- }
+ if (cache == null) {
+ throw new IllegalArgumentException(
+ "Cache '" + cacheName + "' not found for repository interface " + repoInterface.getName()
+ + ". Please, add a cache configuration to ignite configuration"
+ + " or pass autoCreateCache=true to " + RepositoryConfig.class.getName() + " annotation.");
}
}
@@ -164,28 +111,6 @@
return IgniteRepositoryImpl.class;
}
- /** {@inheritDoc} */
- @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
- Assert.notNull(repoItf, "Repository interface must be set.");
- Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
- RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
- Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map "
- + "this repository to the underlying cache.");
-
- Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig "
- + "annotation to map this repository to the underlying cache.");
-
- String cacheName = evaluateExpression(annotation.cacheName());
-
- repoToCache.put(repoItf, cacheName);
-
- repoToIgnite.put(repoItf, igniteForRepoConfig(annotation));
-
- return super.getRepositoryMetadata(repoItf);
- }
-
/**
* Evaluate the SpEL expression
*
@@ -196,33 +121,9 @@
return (String)resolver.evaluate(spelExpression, beanExpressionContext);
}
- /** Control underlying cache creation to avoid cache creation by mistake */
- private IgniteCacheProxy<?, ?> getRepositoryCache(Class<?> repoIf) {
- IgniteProxy ignite = repoToIgnite.get(repoIf);
-
- RepositoryConfig config = repoIf.getAnnotation(RepositoryConfig.class);
-
- String cacheName = repoToCache.get(repoIf);
-
- IgniteCacheProxy<?, ?> c = config.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
-
- if (c == null) {
- throw new IllegalStateException(
- "Cache '" + cacheName + "' not found for repository interface " + repoIf.getName()
- + ". Please, add a cache configuration to ignite configuration"
- + " or pass autoCreateCache=true to org.apache.ignite.springdata20"
- + ".repository.config.RepositoryConfig annotation.");
- }
-
- return c;
- }
-
/** {@inheritDoc} */
@Override protected Object getTargetRepository(RepositoryInformation metadata) {
- IgniteProxy ignite = repoToIgnite.get(metadata.getRepositoryInterface());
-
- return getTargetRepositoryViaReflection(metadata, ignite,
- getRepositoryCache(metadata.getRepositoryInterface()));
+ return getTargetRepositoryViaReflection(metadata, ignite, cache);
}
/** {@inheritDoc} */
@@ -243,8 +144,7 @@
annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
if (key != QueryLookupStrategy.Key.CREATE) {
- return new IgniteRepositoryQuery(metadata, query, mtd, factory,
- getRepositoryCache(metadata.getRepositoryInterface()),
+ return new IgniteRepositoryQuery(metadata, query, mtd, factory, cache,
annotatedIgniteQuery ? DynamicQueryConfig.fromQueryAnnotation(annotation) : null,
evaluationContextProvider);
}
@@ -256,9 +156,8 @@
+ ".config.Query annotation.");
}
- return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
- factory, getRepositoryCache(metadata.getRepositoryInterface()),
- DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
+ return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd, factory,
+ cache, DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
});
}
@@ -290,4 +189,18 @@
// insert
qryUpperCase.matches("^\\s*INSERT\\b.*");
}
+
+ /**
+ * @return Configuration of the specified repository.
+ * @throws IllegalArgumentException If no configuration is specified.
+ * @see RepositoryConfig
+ */
+ static RepositoryConfig getRepositoryConfiguration(Class<?> repoInterface) {
+ RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
+
+ Assert.notNull(cfg, "Invalid configuration for repository " + repoInterface.getName() + ". " +
+ RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
+
+ return cfg;
+ }
}
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
index 5b3d612..bce6dda 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryFactoryBean.java
@@ -62,6 +62,6 @@
/** {@inheritDoc} */
@Override protected RepositoryFactorySupport createRepositoryFactory() {
- return new IgniteRepositoryFactory(ctx);
+ return new IgniteRepositoryFactory(ctx, getObjectType());
}
}
diff --git a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
index b089c22..9410ec2 100644
--- a/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.0-ext/src/main/java/org/apache/ignite/springdata20/repository/support/IgniteRepositoryImpl.java
@@ -49,7 +49,7 @@
*/
@Conditional(ConditionFalse.class)
public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRepository<V, K> {
- /** Error message indicating that operation is spported only if {@link Ignite} instance is used to access the cluster. */
+ /** Error message indicating that operation is supported only if {@link Ignite} instance is used to access the cluster. */
private static final String UNSUPPORTED_ERR_MSG = "Current operation is supported only if Ignite node instance is" +
" used to access the Ignite cluster. See " + RepositoryConfig.class.getName() + "#igniteInstance.";
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
index 6dcadb8..ec2e7ca 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
@@ -17,6 +17,7 @@
package org.apache.ignite.springdata;
+import org.apache.ignite.Ignite;
import org.apache.ignite.springdata.compoundkey.CityRepository;
import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -32,4 +33,9 @@
repo = ctx.getBean(CityRepository.class);
}
+
+ /** {@inheritDoc} */
+ @Override protected Ignite ignite() {
+ return ctx.getBean("igniteServerNode", Ignite.class);
+ }
}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index ae42434..226ee9b 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -18,13 +18,9 @@
package org.apache.ignite.springdata;
import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
import org.apache.ignite.springdata.misc.PersonRepository;
-import org.apache.ignite.springdata.misc.IgniteClientConfigRepository;
-import org.apache.ignite.springdata20.repository.support.IgniteRepositoryFactory;
import org.apache.ignite.testframework.GridTestUtils;
-import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
@@ -47,16 +43,4 @@
" org.apache.ignite.springdata.misc.PersonRepository#textQueryByFirstNameWithProjectionNamedParameter" +
" method configuration or use Ignite node instance to connect to the Ignite cluster.");
}
-
- /**
- * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
- */
- @Test
- public void testRepositoryWithClientConfiguration() {
- IgniteRepositoryFactory factory = new IgniteRepositoryFactory(ctx);
-
- IgniteClientConfigRepository repo = factory.getRepository(IgniteClientConfigRepository.class);
-
- assertTrue(repo.count() > 0);
- }
}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
index 06e0c28..3a65f29 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
@@ -98,7 +98,7 @@
/** load data*/
public void loadData() throws Exception {
- Ignite ignite = ctx.getBean(Ignite.class);
+ Ignite ignite = ignite();
if (ignite.cacheNames().contains(CACHE_NAME))
ignite.destroyCache(CACHE_NAME);
@@ -124,4 +124,9 @@
assertEquals(AFG_COUNT, repo.findByCountryCode(AFG).size());
assertEquals(QUANDAHAR, repo.findById(QUANDAHAR_ID));
}
+
+ /** */
+ protected Ignite ignite() {
+ return ctx.getBean(Ignite.class);
+ }
}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..4187e28
--- /dev/null
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.springdata;
+
+import java.io.Serializable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata20.repository.IgniteRepository;
+import org.apache.ignite.springdata20.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private static final String CACHE_NAME = "PersonCache";
+
+ /** */
+ private static final int CLI_CONN_PORT = 10810;
+
+ /** */
+ private static final String CLI_NAME = "cli-node";
+
+ /** */
+ private static final String SRV_NAME = "srv-node";
+
+ /** */
+ private static final String LOCAL_HOST = "127.0.0.1";
+
+ /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithIgniteConfiguration() {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+ assertClientNodeIsStopped();
+ }
+
+ /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithClientConfiguration() {
+ checkRepositoryConfiguration(ClientConfigurationApplication.class, IgniteClientConfigRepository.class);
+ }
+
+ /**
+ * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+ * used to access the Ignite cluster.
+ */
+ @Test
+ public void testRepositoryWithExistingIgniteInstance() throws Exception {
+ try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+ assertNotNull(Ignition.ignite(CLI_NAME));
+ }
+ }
+
+ /** Tests repository configuration in case specified cache name is invalid. */
+ @Test
+ public void testRepositoryWithInvalidCacheNameConfiguration() {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(InvalidCacheNameApplication.class);
+
+ assertThrowsAnyCause(log,
+ () -> {
+ ctx.refresh();
+
+ return null;
+ },
+ IllegalArgumentException.class,
+ "Cache 'invalidCache' not found for repository interface" +
+ " org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest$InvalidCacheNameRepository." +
+ " Please, add a cache configuration to ignite configuration or pass autoCreateCache=true to" +
+ " org.apache.ignite.springdata20.repository.config.RepositoryConfig annotation.");
+ }
+
+ assertClientNodeIsStopped();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ grid(SRV_NAME).cache(CACHE_NAME).clear();
+ }
+
+ /** */
+ private void assertClientNodeIsStopped() {
+ assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ startGrid(getIgniteConfiguration(SRV_NAME, false));
+ }
+
+ /**
+ * Checks that repository created based on specified Spring application configuration is properly initialized and
+ * got access to the Ignite cluster.
+ */
+ private void checkRepositoryConfiguration(
+ Class<?> cfgCls,
+ Class<? extends IgniteRepository<Object, Serializable>> repoCls
+ ) {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(cfgCls);
+ ctx.refresh();
+
+ IgniteRepository<Object, Serializable> repo = ctx.getBean(repoCls);
+
+ IgniteCache<Object, Serializable> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+ assertEquals(0, repo.count());
+ assertEquals(0, cache.size());
+
+ int key = 0;
+
+ repo.save(key, "1");
+
+ assertEquals(1, repo.count());
+ assertNotNull(cache.get(key));
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheNameRepository.class))
+ public static class InvalidCacheNameApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteConfiguration() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteConfigRepository.class))
+ public static class IgniteConfigurationApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteConfiguration() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteClientConfigRepository.class))
+ public static class ClientConfigurationApplication {
+ /** Ignite client configuration bean. */
+ @Bean
+ public ClientConfiguration clientConfiguration() {
+ return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+ }
+ }
+
+ /** Repository for testing configuration approach through {@link IgniteConfiguration}. */
+ @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "igniteConfiguration")
+ public interface IgniteConfigRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** Repository for testing repository configuration approach through {@link ClientConfiguration}. */
+ @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
+ public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** Repository for testing application behavior in case invalid cache is specified in the repository configuration. */
+ @RepositoryConfig(cacheName = "invalidCache", igniteCfg = "igniteConfiguration")
+ public interface InvalidCacheNameRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** */
+ private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+ return new IgniteConfiguration()
+ .setIgniteInstanceName(name)
+ .setClientMode(clientMode)
+ .setLocalHost(LOCAL_HOST)
+ .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+ .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+ .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+ }
+}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index 2122231..7b69075 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -72,6 +72,12 @@
return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_ONE, CLI_CONN_PORT));
}
+ /** */
+ @Bean
+ public Ignite igniteSecondServerNode() {
+ return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
+ }
+
/** Ignite client instance bean with default name. */
@Bean
public IgniteClient igniteInstance() {
@@ -82,18 +88,10 @@
/** Ignite client instance bean with non-default name. */
@Bean
public IgniteClient igniteInstanceTWO() {
- Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
-
return Ignition.startClient(new ClientConfiguration().setAddresses("127.0.0.1:10801"));
}
- /** Ignite client configuraition bean. */
- @Bean
- public ClientConfiguration clientConfiguration() {
- return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
- }
-
- /** Ingite configuration for server node. */
+ /** */
private static IgniteConfiguration igniteConfiguration(String igniteInstanceName, int cliConnPort) {
return new IgniteConfiguration()
.setIgniteInstanceName(igniteInstanceName)
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
deleted file mode 100644
index ccbfa08..0000000
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.springdata.misc;
-
-import java.io.Serializable;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.springdata20.repository.IgniteRepository;
-import org.apache.ignite.springdata20.repository.config.RepositoryConfig;
-
-/** Repository for testing repository configurion approach through {@link ClientConfiguration}. */
-@RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
-public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
- // No-op.
-}
diff --git a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
index 6c26078..88879e2 100644
--- a/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
+++ b/modules/spring-data-2.0-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData2TestSuite.java
@@ -21,6 +21,7 @@
import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
import org.apache.ignite.springdata.IgniteSpringDataCrudSelfExpressionTest;
import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
@@ -36,6 +37,7 @@
IgniteSpringDataQueriesSelfTest.class,
IgniteSpringDataCrudSelfExpressionTest.class,
IgniteSpringDataCompoundKeyTest.class,
+ IgniteSpringDataConnectionConfigurationTest.class,
IgniteClientSpringDataCrudSelfTest.class,
IgniteClientSpringDataQueriesSelfTest.class,
IgniteClientSpringDataCompoundKeyTest.class
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
index ad465c3..560ee2e 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/EnableIgniteRepositories.java
@@ -22,7 +22,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-
import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactoryBean;
import org.apache.ignite.springdata22.repository.support.IgniteRepositoryImpl;
import org.springframework.beans.factory.FactoryBean;
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
index 4989196..cf6db05 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -18,15 +18,28 @@
import java.util.Collection;
import java.util.Collections;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
import org.apache.ignite.springdata22.repository.IgniteRepository;
+import org.apache.ignite.springdata22.repository.support.IgniteProxyFactory;
import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
+
+import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;
/**
* Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
*/
public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+ /** Name of the auto-registered Ignite proxy factory bean. */
+ private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
+ /** Name of the auto-registered Ignite proxy bean prototype. */
+ private static final String IGNITE_PROXY_BEAN_NAME = "igniteProxy";
+
/** {@inheritDoc} */
@Override public String getModuleName() {
return "Apache Ignite";
@@ -46,4 +59,22 @@
@Override protected Collection<Class<?>> getIdentifyingTypes() {
return Collections.singleton(IgniteRepository.class);
}
+
+ /** {@inheritDoc} */
+ @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+ registerIfNotAlreadyRegistered(
+ () -> BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+ registry,
+ IGNITE_PROXY_FACTORY_BEAN_NAME,
+ cfg);
+
+ registerIfNotAlreadyRegistered(
+ () -> BeanDefinitionBuilder.genericBeanDefinition(IgniteProxy.class)
+ .setScope(SCOPE_PROTOTYPE)
+ .setFactoryMethodOnBean("igniteProxy", IGNITE_PROXY_FACTORY_BEAN_NAME)
+ .getBeanDefinition(),
+ registry,
+ IGNITE_PROXY_BEAN_NAME,
+ cfg);
+ }
}
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..ac56e00
--- /dev/null
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,140 @@
+/*
+ * 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.springdata22.repository.support;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.expression.StandardBeanExpressionResolver;
+
+import static org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactory.getRepositoryConfiguration;
+
+/**
+ * Represents factory for obtaining instances of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory implements ApplicationContextAware, DisposableBean {
+ /** Spring application expression resolver. */
+ private final BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
+
+ /** Repositories associated with Ignite proxy. */
+ private final Map<Class<?>, IgniteProxy> igniteProxies = new ConcurrentHashMap<>();
+
+ /** Spring application context. */
+ private ApplicationContext ctx;
+
+ /** Spring application bean expression context. */
+ private BeanExpressionContext beanExpressionCtx;
+
+ /**
+ * @param repoInterface The repository interface class for which {@link IgniteProxy} will be created.
+ * @return {@link IgniteProxy} instance.
+ */
+ public IgniteProxy igniteProxy(Class<?> repoInterface) {
+ return igniteProxies.computeIfAbsent(repoInterface, k -> createIgniteProxy(repoInterface));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+ this.ctx = ctx;
+
+ beanExpressionCtx = new BeanExpressionContext(
+ new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+ null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void destroy() throws Exception {
+ Set<IgniteProxy> proxies = new HashSet<>(igniteProxies.values());
+
+ Exception destroyE = null;
+
+ for (IgniteProxy proxy : proxies) {
+ if (proxy instanceof AutoCloseable) {
+ try {
+ ((AutoCloseable)proxy).close();
+ }
+ catch (Exception e) {
+ if (destroyE == null)
+ destroyE = e;
+ else
+ destroyE.addSuppressed(e);
+ }
+ }
+ }
+
+ if (destroyE != null)
+ throw destroyE;
+ }
+
+ /**
+ * Creates {@link IgniteProxy} to be used for providing access to the Ignite cluster for specified repository.
+ *
+ * @param repoInterface {@link Class} instance of the repository interface.
+ * @return Instance of {@link IgniteProxy} associated with specified repository.
+ *
+ * @see RepositoryConfig
+ */
+ private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
+ RepositoryConfig repoCfg = getRepositoryConfiguration(repoInterface);
+
+ Object connCfg;
+
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteInstance()));
+ }
+ catch (BeansException ex) {
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteCfg()));
+ }
+ catch (BeansException ex2) {
+ try {
+ connCfg = ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class);
+ }
+ catch (BeansException ex3) {
+ throw new IllegalArgumentException("Invalid configuration for repository " +
+ repoInterface.getName() + ". No beans were found that provide connection configuration to the" +
+ " Ignite cluster. Check \"igniteInstance\", \"igniteCfg\", \"igniteSpringCfgPath\" parameters" +
+ " of " + RepositoryConfig.class.getName() + " repository annotation.");
+ }
+ }
+ }
+
+ return IgniteProxy.of(connCfg);
+ }
+
+ /**
+ * Evaluates the SpEL expression.
+ *
+ * @param spelExpression SpEL expression
+ * @return The result of evaluation of the SpEL expression.
+ */
+ private String evaluateExpression(String spelExpression) {
+ return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
+ }
+}
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
index a9c7ad2..4494c14 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactory.java
@@ -16,27 +16,15 @@
*/
package org.apache.ignite.springdata22.repository.support;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata22.repository.IgniteRepository;
import org.apache.ignite.springdata22.repository.config.DynamicQueryConfig;
import org.apache.ignite.springdata22.repository.config.Query;
import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
import org.apache.ignite.springdata22.repository.query.IgniteQuery;
import org.apache.ignite.springdata22.repository.query.IgniteQueryGenerator;
import org.apache.ignite.springdata22.repository.query.IgniteRepositoryQuery;
-import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
@@ -62,85 +50,44 @@
* @author Manuel Núñez (manuel.nunez@hawkore.com)
*/
public class IgniteRepositoryFactory extends RepositoryFactorySupport {
- /** Spring application context */
- private final ApplicationContext ctx;
-
- /** Spring application bean factory */
- private final DefaultListableBeanFactory beanFactory;
-
/** Spring application expression resolver */
private final StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
/** Spring application bean expression context */
private final BeanExpressionContext beanExpressionContext;
- /** Mapping of a repository to a cache. */
- private final Map<Class<?>, String> repoToCache = new HashMap<>();
+ /** Ignite cache proxy instance associated with the current repository. */
+ private final IgniteCacheProxy<?, ?> cache;
- /** Mapping of a repository to a ignite instance. */
- private final Map<Class<?>, IgniteProxy> repoToIgnite = new HashMap<>();
+ /** Ignite proxy instance associated with the current repository. */
+ private final IgniteProxy ignite;
/**
- * Creates the factory with initialized {@link Ignite} instance.
- *
- * @param ctx the ctx
+ * @param ctx Spring Application context.
+ * @param repoInterface Repository interface.
*/
- public IgniteRepositoryFactory(ApplicationContext ctx) {
- this.ctx = ctx;
+ public IgniteRepositoryFactory(ApplicationContext ctx, Class<?> repoInterface) {
+ ignite = ctx.getBean(IgniteProxy.class, repoInterface);
- beanFactory = new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory());
+ beanExpressionContext = new BeanExpressionContext(
+ new DefaultListableBeanFactory(ctx.getAutowireCapableBeanFactory()),
+ null);
- beanExpressionContext = new BeanExpressionContext(beanFactory, null);
- }
+ RepositoryConfig cfg = getRepositoryConfiguration(repoInterface);
- /** */
- private IgniteProxy igniteForRepoConfig(RepositoryConfig config) {
- try {
- Object igniteInstanceBean = ctx.getBean(evaluateExpression(config.igniteInstance()));
+ String cacheName = evaluateExpression(cfg.cacheName());
- if (igniteInstanceBean instanceof Ignite)
- return new IgniteProxyImpl((Ignite)igniteInstanceBean);
- else if (igniteInstanceBean instanceof IgniteClient)
- return new IgniteClientProxy((IgniteClient)igniteInstanceBean);
+ Assert.hasText(cacheName, "Invalid configuration for repository " + repoInterface.getName() +
+ ". Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+ " annotation to map this repository to the underlying cache.");
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
- " \"igniteInstance\" property of repository configuration must be one of the following types: " +
- Ignite.class.getName() + ", " + IgniteClient.class.getName());
- }
- catch (BeansException ex) {
- try {
- Object igniteCfgBean = ctx.getBean(evaluateExpression(config.igniteCfg()));
+ cache = cfg.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
- if (igniteCfgBean instanceof IgniteConfiguration) {
- try {
- // first try to attach to existing ignite instance
- return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)igniteCfgBean).getIgniteInstanceName()));
- }
- catch (Exception ignored) {
- // nop
- }
- return new IgniteProxyImpl(Ignition.start((IgniteConfiguration)igniteCfgBean));
- }
- else if (igniteCfgBean instanceof ClientConfiguration)
- return new IgniteClientProxy(Ignition.startClient((ClientConfiguration)igniteCfgBean));
-
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
- " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
- IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
-
- }
- catch (BeansException ex2) {
- try {
- String igniteSpringCfgPath = evaluateExpression(config.igniteSpringCfgPath());
- String path = (String)ctx.getBean(igniteSpringCfgPath);
- return new IgniteProxyImpl(Ignition.start(path));
- }
- catch (BeansException ex3) {
- throw new IgniteException("Failed to initialize Ignite repository factory. No beans required for" +
- " repository configuration were found. Check \"igniteInstance\", \"igniteCfg\"," +
- " \"igniteSpringCfgPath\" parameters of " + RepositoryConfig.class.getName() + "class.");
- }
- }
+ if (cache == null) {
+ throw new IllegalArgumentException(
+ "Cache '" + cacheName + "' not found for repository interface " + repoInterface.getName()
+ + ". Please, add a cache configuration to ignite configuration"
+ + " or pass autoCreateCache=true to " + RepositoryConfig.class.getName() + " annotation.");
}
}
@@ -164,28 +111,6 @@
return IgniteRepositoryImpl.class;
}
- /** {@inheritDoc} */
- @Override protected synchronized RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
- Assert.notNull(repoItf, "Repository interface must be set.");
- Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
- RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
- Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map "
- + "this repository to the underlying cache.");
-
- Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig "
- + "annotation to map this repository to the underlying cache.");
-
- String cacheName = evaluateExpression(annotation.cacheName());
-
- repoToCache.put(repoItf, cacheName);
-
- repoToIgnite.put(repoItf, igniteForRepoConfig(annotation));
-
- return super.getRepositoryMetadata(repoItf);
- }
-
/**
* Evaluate the SpEL expression
*
@@ -196,33 +121,9 @@
return (String)resolver.evaluate(spelExpression, beanExpressionContext);
}
- /** Control underlying cache creation to avoid cache creation by mistake */
- private IgniteCacheProxy<?, ?> getRepositoryCache(Class<?> repoIf) {
- IgniteProxy ignite = repoToIgnite.get(repoIf);
-
- RepositoryConfig config = repoIf.getAnnotation(RepositoryConfig.class);
-
- String cacheName = repoToCache.get(repoIf);
-
- IgniteCacheProxy<?, ?> c = config.autoCreateCache() ? ignite.getOrCreateCache(cacheName) : ignite.cache(cacheName);
-
- if (c == null) {
- throw new IllegalStateException(
- "Cache '" + cacheName + "' not found for repository interface " + repoIf.getName()
- + ". Please, add a cache configuration to ignite configuration"
- + " or pass autoCreateCache=true to org.apache.ignite.springdata22"
- + ".repository.config.RepositoryConfig annotation.");
- }
-
- return c;
- }
-
/** {@inheritDoc} */
@Override protected Object getTargetRepository(RepositoryInformation metadata) {
- IgniteProxy ignite = repoToIgnite.get(metadata.getRepositoryInterface());
-
- return getTargetRepositoryViaReflection(metadata, ignite,
- getRepositoryCache(metadata.getRepositoryInterface()));
+ return getTargetRepositoryViaReflection(metadata, ignite, cache);
}
/** {@inheritDoc} */
@@ -243,8 +144,7 @@
annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
if (key != QueryLookupStrategy.Key.CREATE) {
- return new IgniteRepositoryQuery(metadata, query, mtd, factory,
- getRepositoryCache(metadata.getRepositoryInterface()),
+ return new IgniteRepositoryQuery(metadata, query, mtd, factory, cache,
annotatedIgniteQuery ? DynamicQueryConfig.fromQueryAnnotation(annotation) : null,
evaluationContextProvider);
}
@@ -256,9 +156,8 @@
+ ".config.Query annotation.");
}
- return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
- factory, getRepositoryCache(metadata.getRepositoryInterface()),
- DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
+ return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd, factory,
+ cache, DynamicQueryConfig.fromQueryAnnotation(annotation), evaluationContextProvider);
});
}
@@ -290,4 +189,18 @@
// insert
qryUpperCase.matches("^\\s*INSERT\\b.*");
}
+
+ /**
+ * @return Configuration of the specified repository.
+ * @throws IllegalArgumentException If no configuration is specified.
+ * @see RepositoryConfig
+ */
+ static RepositoryConfig getRepositoryConfiguration(Class<?> repoInterface) {
+ RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
+
+ Assert.notNull(cfg, "Invalid configuration for repository " + repoInterface.getName() + ". " +
+ RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
+
+ return cfg;
+ }
}
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
index ece9f31..9d6794d 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryFactoryBean.java
@@ -62,6 +62,6 @@
/** {@inheritDoc} */
@Override protected RepositoryFactorySupport createRepositoryFactory() {
- return new IgniteRepositoryFactory(ctx);
+ return new IgniteRepositoryFactory(ctx, getObjectType());
}
}
diff --git a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
index de0573b..d91da58 100644
--- a/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
+++ b/modules/spring-data-2.2-ext/src/main/java/org/apache/ignite/springdata22/repository/support/IgniteRepositoryImpl.java
@@ -49,7 +49,7 @@
*/
@Conditional(ConditionFalse.class)
public class IgniteRepositoryImpl<V, K extends Serializable> implements IgniteRepository<V, K> {
- /** Error message indicating that operation is spported only if {@link Ignite} instance is used to access the cluster. */
+ /** Error message indicating that operation is supported only if {@link Ignite} instance is used to access the cluster. */
private static final String UNSUPPORTED_ERR_MSG = "Current operation is supported only if Ignite node instance is" +
" used to access the Ignite cluster. See " + RepositoryConfig.class.getName() + "#igniteInstance.";
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
index 6dcadb8..ec2e7ca 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCompoundKeyTest.java
@@ -17,6 +17,7 @@
package org.apache.ignite.springdata;
+import org.apache.ignite.Ignite;
import org.apache.ignite.springdata.compoundkey.CityRepository;
import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -32,4 +33,9 @@
repo = ctx.getBean(CityRepository.class);
}
+
+ /** {@inheritDoc} */
+ @Override protected Ignite ignite() {
+ return ctx.getBean("igniteServerNode", Ignite.class);
+ }
}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index d1597d9..226ee9b 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -18,13 +18,9 @@
package org.apache.ignite.springdata;
import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
-import org.apache.ignite.springdata.misc.IgniteClientConfigRepository;
import org.apache.ignite.springdata.misc.PersonRepository;
-import org.apache.ignite.springdata22.repository.support.IgniteRepositoryFactory;
import org.apache.ignite.testframework.GridTestUtils;
-import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
@@ -47,16 +43,4 @@
" org.apache.ignite.springdata.misc.PersonRepository#textQueryByFirstNameWithProjectionNamedParameter" +
" method configuration or use Ignite node instance to connect to the Ignite cluster.");
}
-
- /**
- * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
- */
- @Test
- public void testRepositoryWithClientConfiguration() {
- IgniteRepositoryFactory factory = new IgniteRepositoryFactory(ctx);
-
- IgniteClientConfigRepository repo = factory.getRepository(IgniteClientConfigRepository.class);
-
- assertTrue(repo.count() > 0);
- }
}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
index 06e0c28..3a65f29 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCompoundKeyTest.java
@@ -98,7 +98,7 @@
/** load data*/
public void loadData() throws Exception {
- Ignite ignite = ctx.getBean(Ignite.class);
+ Ignite ignite = ignite();
if (ignite.cacheNames().contains(CACHE_NAME))
ignite.destroyCache(CACHE_NAME);
@@ -124,4 +124,9 @@
assertEquals(AFG_COUNT, repo.findByCountryCode(AFG).size());
assertEquals(QUANDAHAR, repo.findById(QUANDAHAR_ID));
}
+
+ /** */
+ protected Ignite ignite() {
+ return ctx.getBean(Ignite.class);
+ }
}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..68c421a
--- /dev/null
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.springdata;
+
+import java.io.Serializable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata22.repository.IgniteRepository;
+import org.apache.ignite.springdata22.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private static final String CACHE_NAME = "PersonCache";
+
+ /** */
+ private static final int CLI_CONN_PORT = 10810;
+
+ /** */
+ private static final String CLI_NAME = "cli-node";
+
+ /** */
+ private static final String SRV_NAME = "srv-node";
+
+ /** */
+ private static final String LOCAL_HOST = "127.0.0.1";
+
+ /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithIgniteConfiguration() {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+ assertClientNodeIsStopped();
+ }
+
+ /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithClientConfiguration() {
+ checkRepositoryConfiguration(ClientConfigurationApplication.class, IgniteClientConfigRepository.class);
+ }
+
+ /**
+ * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+ * used to access the Ignite cluster.
+ */
+ @Test
+ public void testRepositoryWithExistingIgniteInstance() throws Exception {
+ try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class, IgniteConfigRepository.class);
+
+ assertNotNull(Ignition.ignite(CLI_NAME));
+ }
+ }
+
+ /** Tests repository configuration in case specified cache name is invalid. */
+ @Test
+ public void testRepositoryWithInvalidCacheNameConfiguration() {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(InvalidCacheNameApplication.class);
+
+ assertThrowsAnyCause(log,
+ () -> {
+ ctx.refresh();
+
+ return null;
+ },
+ IllegalArgumentException.class,
+ "Cache 'invalidCache' not found for repository interface" +
+ " org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest$InvalidCacheNameRepository." +
+ " Please, add a cache configuration to ignite configuration or pass autoCreateCache=true to" +
+ " org.apache.ignite.springdata22.repository.config.RepositoryConfig annotation.");
+ }
+
+ assertClientNodeIsStopped();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ grid(SRV_NAME).cache(CACHE_NAME).clear();
+ }
+
+ /** */
+ private void assertClientNodeIsStopped() {
+ assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ startGrid(getIgniteConfiguration(SRV_NAME, false));
+ }
+
+ /**
+ * Checks that repository created based on specified Spring application configuration is properly initialized and
+ * got access to the Ignite cluster.
+ */
+ private void checkRepositoryConfiguration(
+ Class<?> cfgCls,
+ Class<? extends IgniteRepository<Object, Serializable>> repoCls
+ ) {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(cfgCls);
+ ctx.refresh();
+
+ IgniteRepository<Object, Serializable> repo = ctx.getBean(repoCls);
+
+ IgniteCache<Object, Serializable> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+ assertEquals(0, repo.count());
+ assertEquals(0, cache.size());
+
+ int key = 0;
+
+ repo.save(key, "1");
+
+ assertEquals(1, repo.count());
+ assertNotNull(cache.get(key));
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheNameRepository.class))
+ public static class InvalidCacheNameApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteConfiguration() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteConfigRepository.class))
+ public static class IgniteConfigurationApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteConfiguration() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteClientConfigRepository.class))
+ public static class ClientConfigurationApplication {
+ /** Ignite client configuration bean. */
+ @Bean
+ public ClientConfiguration clientConfiguration() {
+ return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+ }
+ }
+
+ /** Repository for testing configuration approach through {@link IgniteConfiguration}. */
+ @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "igniteConfiguration")
+ public interface IgniteConfigRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** Repository for testing repository configuration approach through {@link ClientConfiguration}. */
+ @RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
+ public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** Repository for testing application behavior in case invalid cache is specified in the repository configuration. */
+ @RepositoryConfig(cacheName = "invalidCache", igniteCfg = "igniteConfiguration")
+ public interface InvalidCacheNameRepository extends IgniteRepository<Object, Serializable> {
+ // No-op.
+ }
+
+ /** */
+ private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+ return new IgniteConfiguration()
+ .setIgniteInstanceName(name)
+ .setClientMode(clientMode)
+ .setLocalHost(LOCAL_HOST)
+ .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+ .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+ .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+ }
+}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index c5d159a..ad255d0 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -72,6 +72,12 @@
return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_ONE, CLI_CONN_PORT));
}
+ /** */
+ @Bean
+ public Ignite igniteSecondServerNode() {
+ return Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
+ }
+
/** Ignite client instance bean with default name. */
@Bean
public IgniteClient igniteInstance() {
@@ -82,18 +88,10 @@
/** Ignite client instance bean with non-default name. */
@Bean
public IgniteClient igniteInstanceTWO() {
- Ignition.start(igniteConfiguration(IGNITE_INSTANCE_TWO, 10801));
-
return Ignition.startClient(new ClientConfiguration().setAddresses("127.0.0.1:10801"));
}
- /** Ignite client configuraition bean. */
- @Bean
- public ClientConfiguration clientConfiguration() {
- return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
- }
-
- /** Ingite configuration for server node. */
+ /** */
private static IgniteConfiguration igniteConfiguration(String igniteInstanceName, int cliConnPort) {
return new IgniteConfiguration()
.setIgniteInstanceName(igniteInstanceName)
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
deleted file mode 100644
index 23a9d8e..0000000
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientConfigRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.springdata.misc;
-
-import java.io.Serializable;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.springdata22.repository.IgniteRepository;
-import org.apache.ignite.springdata22.repository.config.RepositoryConfig;
-
-/** Repository for testing repository configurion approach through {@link ClientConfiguration}. */
-@RepositoryConfig(cacheName = "PersonCache", igniteCfg = "clientConfiguration")
-public interface IgniteClientConfigRepository extends IgniteRepository<Object, Serializable> {
- // No-op.
-}
diff --git a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
index 4363f74..899118b 100644
--- a/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
+++ b/modules/spring-data-2.2-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringData22TestSuite.java
@@ -21,6 +21,7 @@
import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
import org.apache.ignite.springdata.IgniteSpringDataCrudSelfExpressionTest;
import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
@@ -36,6 +37,7 @@
IgniteSpringDataQueriesSelfTest.class,
IgniteSpringDataCrudSelfExpressionTest.class,
IgniteSpringDataCompoundKeyTest.class,
+ IgniteSpringDataConnectionConfigurationTest.class,
IgniteClientSpringDataCrudSelfTest.class,
IgniteClientSpringDataQueriesSelfTest.class,
IgniteClientSpringDataCompoundKeyTest.class
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java
new file mode 100644
index 0000000..73e1681
--- /dev/null
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteClientProxy.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.springdata.proxy;
+
+import org.apache.ignite.client.IgniteClient;
+
+/** Extends {@link IgniteClientProxy} with the ability to close underlying thin client instance. */
+public class ClosableIgniteClientProxy extends IgniteClientProxy implements AutoCloseable {
+ /**
+ * @param cli Ignite client instance.
+ */
+ public ClosableIgniteClientProxy(IgniteClient cli) {
+ super(cli);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws Exception {
+ cli.close();
+ }
+}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java
new file mode 100644
index 0000000..79807e4
--- /dev/null
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/ClosableIgniteProxyImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.springdata.proxy;
+
+import org.apache.ignite.Ignite;
+
+/** Extends {@link IgniteProxyImpl} with the ability to close underlying Ignite instance. */
+public class ClosableIgniteProxyImpl extends IgniteProxyImpl implements AutoCloseable {
+ /**
+ * @param ignite Ignite instance.
+ */
+ public ClosableIgniteProxyImpl(Ignite ignite) {
+ super(ignite);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws Exception {
+ ignite.close();
+ }
+}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
index ac29eb4..3c5c4d2 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteCacheProxy.java
@@ -26,7 +26,7 @@
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.client.ClientCache;
-/** Reperesents Ignite cache operations required by Spring Data. */
+/** Represents Ignite cache operations required by Spring Data. */
public interface IgniteCacheProxy<K, V> extends Iterable<Cache.Entry<K, V>> {
/**
* Gets an entry from the cache.
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
index ae50823..00dc42e 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteClientProxy.java
@@ -17,12 +17,13 @@
package org.apache.ignite.springdata.proxy;
+import java.util.Objects;
import org.apache.ignite.client.IgniteClient;
/** Implementation of {@link IgniteProxy} that provides access to Ignite cluster through {@link IgniteClient} instance. */
public class IgniteClientProxy implements IgniteProxy {
/** {@link IgniteClient} instance to which operations are delegated. */
- private final IgniteClient cli;
+ protected final IgniteClient cli;
/** */
public IgniteClientProxy(IgniteClient cli) {
@@ -38,4 +39,20 @@
@Override public <K, V> IgniteCacheProxy<K, V> cache(String name) {
return new IgniteCacheClientProxy<>(cli.cache(name));
}
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object other) {
+ if (this == other)
+ return true;
+
+ if (other == null || getClass() != other.getClass())
+ return false;
+
+ return Objects.equals(cli, ((IgniteClientProxy)other).cli);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return cli.hashCode();
+ }
}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
index e798274..62e0d5c 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxy.java
@@ -17,7 +17,13 @@
package org.apache.ignite.springdata.proxy;
-/** Reperesents Ignite cluster operations required by Spring Data. */
+import org.apache.ignite.Ignite;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+
+/** Represents Ignite cluster operations required by Spring Data. */
public interface IgniteProxy {
/**
* Gets existing cache with the given name or creates new one.
@@ -34,4 +40,32 @@
* @return Cache proxy that provides access to cache with specified name or {@code null} if it doesn't exist.
*/
public <K, V> IgniteCacheProxy<K, V> cache(String name);
+
+ /**
+ * @param connObj Object that will be used to obtain underlying Ignite client instance to access the Ignite cluster.
+ * @return Ignite proxy instance.
+ */
+ public static IgniteProxy of(Object connObj) {
+ if (connObj instanceof Ignite)
+ return new IgniteProxyImpl((Ignite)connObj);
+ else if (connObj instanceof IgniteConfiguration) {
+ try {
+ return new IgniteProxyImpl(Ignition.ignite(((IgniteConfiguration)connObj).getIgniteInstanceName()));
+ }
+ catch (Exception ignored) {
+ // No-op.
+ }
+
+ return new ClosableIgniteProxyImpl(Ignition.start((IgniteConfiguration)connObj));
+ }
+ else if (connObj instanceof String)
+ return new ClosableIgniteProxyImpl(Ignition.start((String)connObj));
+ else if (connObj instanceof IgniteClient)
+ return new IgniteClientProxy((IgniteClient)connObj);
+ else if (connObj instanceof ClientConfiguration)
+ return new ClosableIgniteClientProxy(Ignition.startClient((ClientConfiguration)connObj));
+
+ throw new IllegalArgumentException(
+ "Object of type " + connObj.getClass().getName() + " can not be used to connect to the Ignite cluster.");
+ }
}
diff --git a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
index 96b46a7..85acceb 100644
--- a/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
+++ b/modules/spring-data-commons/src/main/java/org/apache/ignite/springdata/proxy/IgniteProxyImpl.java
@@ -17,12 +17,14 @@
package org.apache.ignite.springdata.proxy;
+import java.util.Objects;
import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
/** Implementation of {@link IgniteProxy} that provides access to Ignite cluster through {@link Ignite} instance. */
public class IgniteProxyImpl implements IgniteProxy {
/** {@link Ignite} instance to which operations are delegated. */
- private final Ignite ignite;
+ protected final Ignite ignite;
/** */
public IgniteProxyImpl(Ignite ignite) {
@@ -36,11 +38,29 @@
/** {@inheritDoc} */
@Override public <K, V> IgniteCacheProxy<K, V> cache(String name) {
- return new IgniteCacheProxyImpl<>(ignite.cache(name));
+ IgniteCache<K, V> cache = ignite.cache(name);
+
+ return cache == null ? null : new IgniteCacheProxyImpl<>(cache);
}
/** @return {@link Ignite} instance to which operations are delegated. */
public Ignite delegate() {
return ignite;
}
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object other) {
+ if (this == other)
+ return true;
+
+ if (other == null || getClass() != other.getClass())
+ return false;
+
+ return Objects.equals(ignite, ((IgniteProxyImpl)other).ignite);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return ignite.hashCode();
+ }
}
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
index 630690a..6f21b59 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/config/IgniteRepositoryConfigurationExtension.java
@@ -19,14 +19,21 @@
import java.util.Collection;
import java.util.Collections;
import org.apache.ignite.springdata.repository.IgniteRepository;
+import org.apache.ignite.springdata.repository.support.IgniteProxyFactory;
import org.apache.ignite.springdata.repository.support.IgniteRepositoryFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
+import org.springframework.data.repository.config.RepositoryConfigurationSource;
/**
* Apache Ignite specific implementation of {@link RepositoryConfigurationExtension}.
*/
public class IgniteRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
+ /** Name of the auto-registered Ignite proxy factory bean. */
+ private static final String IGNITE_PROXY_FACTORY_BEAN_NAME = "igniteProxyFactory";
+
/** {@inheritDoc} */
@Override public String getModuleName() {
return "Apache Ignite";
@@ -46,4 +53,13 @@
@Override protected Collection<Class<?>> getIdentifyingTypes() {
return Collections.<Class<?>>singleton(IgniteRepository.class);
}
+
+ /** {@inheritDoc} */
+ @Override public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource cfg) {
+ registerIfNotAlreadyRegistered(
+ BeanDefinitionBuilder.genericBeanDefinition(IgniteProxyFactory.class).getBeanDefinition(),
+ registry,
+ IGNITE_PROXY_FACTORY_BEAN_NAME,
+ cfg);
+ }
}
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java
new file mode 100644
index 0000000..3585287
--- /dev/null
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteProxyFactory.java
@@ -0,0 +1,87 @@
+/*
+ * 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.springdata.repository.support;
+
+import org.apache.ignite.springdata.proxy.IgniteProxy;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * Represents factory for obtaining instance of {@link IgniteProxy} that provide client-independent connection to the
+ * Ignite cluster.
+ */
+public class IgniteProxyFactory extends AbstractFactoryBean<IgniteProxy> implements ApplicationContextAware {
+ /** Name of the bean that stores Ignite client instance to access the Ignite cluster. */
+ private static final String IGNITE_INSTANCE_BEAN_NAME = "igniteInstance";
+
+ /** Name of the bean that stores the configuration to instantiate the Ignite client. */
+ private static final String IGNITE_CONFIG_BEAN_NAME = "igniteCfg";
+
+ /** Name of the bean that stores the Spring configuration path to instantiate the Ignite client. */
+ private static final String IGNITE_SPRING_CONFIG_PATH_BEAN_NAME= "igniteSpringCfgPath";
+
+ /** Spring application context. */
+ private ApplicationContext ctx;
+
+ /** {@inheritDoc} */
+ @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+ this.ctx = ctx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void destroy() throws Exception {
+ Object igniteProxy = getObject();
+
+ if (igniteProxy instanceof AutoCloseable)
+ ((AutoCloseable)igniteProxy).close();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<?> getObjectType() {
+ return IgniteProxy.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteProxy createInstance() {
+ Object connCfg;
+
+ try {
+ connCfg = ctx.getBean(IGNITE_INSTANCE_BEAN_NAME);
+ }
+ catch (BeansException ex) {
+ try {
+ connCfg = ctx.getBean(IGNITE_CONFIG_BEAN_NAME);
+ }
+ catch (BeansException ex2) {
+ try {
+ connCfg = ctx.getBean(IGNITE_SPRING_CONFIG_PATH_BEAN_NAME, String.class);
+ }
+ catch (BeansException ex3) {
+ throw new IllegalArgumentException("No beans were found that provide connection configuration to" +
+ " the Ignite cluster. One of the beans with the following names is required : \"" +
+ IGNITE_INSTANCE_BEAN_NAME + "\", \"" + IGNITE_CONFIG_BEAN_NAME + "\" or \"" +
+ IGNITE_SPRING_CONFIG_PATH_BEAN_NAME + "\".");
+ }
+ }
+ }
+
+ return IgniteProxy.of(connCfg);
+ }
+}
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
index 5fc0ba2..8649733 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
@@ -18,17 +18,8 @@
import java.io.Serializable;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.ignite.Ignite;
-import org.apache.ignite.Ignition;
-import org.apache.ignite.client.IgniteClient;
-import org.apache.ignite.configuration.ClientConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
import org.apache.ignite.springdata.proxy.IgniteProxy;
-import org.apache.ignite.springdata.proxy.IgniteProxyImpl;
-import org.apache.ignite.springdata.proxy.IgniteClientProxy;
-import org.apache.ignite.springdata.repository.IgniteRepository;
import org.apache.ignite.springdata.repository.config.Query;
import org.apache.ignite.springdata.repository.config.RepositoryConfig;
import org.apache.ignite.springdata.repository.query.IgniteQuery;
@@ -51,52 +42,28 @@
* Crucial for spring-data functionality class. Create proxies for repositories.
*/
public class IgniteRepositoryFactory extends RepositoryFactorySupport {
- /** Ignite instance */
- private IgniteProxy ignite;
-
- /** Mapping of a repository to a cache. */
- private final Map<Class<?>, String> repoToCache = new HashMap<>();
+ /** Ignite cache proxy instance associated with the current repository. */
+ private final IgniteCacheProxy<?, ?> cache;
/**
- * Creates the factory with initialized {@link Ignite} instance.
+ * Creates the factory with initialized {@link IgniteProxy} instance.
*
- * @param ignite
+ * @param ignite Ignite proxy instance.
+ * @param repoInterface Repository interface.
*/
- public IgniteRepositoryFactory(Ignite ignite) {
- this.ignite = new IgniteProxyImpl(ignite);
- }
+ public IgniteRepositoryFactory(IgniteProxy ignite, Class<?> repoInterface) {
+ RepositoryConfig cfg = repoInterface.getAnnotation(RepositoryConfig.class);
- /** Creates the factory with initialized {@link IgniteClient} instance. */
- public IgniteRepositoryFactory(IgniteClient cli) {
- ignite = new IgniteClientProxy(cli);
- }
+ Assert.notNull(cfg, "Invalid repository configuration [name=" + repoInterface.getName() + "]. " +
+ RepositoryConfig.class.getName() + " annotation must be specified for each repository interface.");
- /**
- * Initializes the factory with provided {@link IgniteConfiguration} that is used to start up an underlying
- * {@link Ignite} instance.
- *
- * @param cfg Ignite configuration.
- */
- public IgniteRepositoryFactory(IgniteConfiguration cfg) {
- this.ignite = new IgniteProxyImpl(Ignition.start(cfg));
- }
+ String cacheName = cfg.cacheName();
- /**
- * Initializes the factory with provided {@link ClientConfiguration} that is used to start up an underlying
- * {@link IgniteClient} instance.
- */
- public IgniteRepositoryFactory(ClientConfiguration cfg) {
- this.ignite = new IgniteClientProxy(Ignition.startClient(cfg));
- }
+ Assert.hasText(cacheName, "Invalid repository configuration [name=" + repoInterface.getName() + "]." +
+ " Set a name of an Apache Ignite cache using " + RepositoryConfig.class.getName() +
+ " annotation to map this repository to the underlying cache.");
- /**
- * Initializes the factory with provided a configuration under {@code springCfgPath} that is used to start up
- * an underlying {@link Ignite} instance.
- *
- * @param springCfgPath A path to Ignite configuration.
- */
- public IgniteRepositoryFactory(String springCfgPath) {
- this.ignite = new IgniteProxyImpl(Ignition.start(springCfgPath));
+ cache = ignite.getOrCreateCache(cacheName);
}
/** {@inheritDoc} */
@@ -118,27 +85,8 @@
}
/** {@inheritDoc} */
- @Override protected RepositoryMetadata getRepositoryMetadata(Class<?> repoItf) {
- Assert.notNull(repoItf, "Repository interface must be set.");
- Assert.isAssignable(IgniteRepository.class, repoItf, "Repository must implement IgniteRepository interface.");
-
- RepositoryConfig annotation = repoItf.getAnnotation(RepositoryConfig.class);
-
- Assert.notNull(annotation, "Set a name of an Apache Ignite cache using @RepositoryConfig annotation to map " +
- "this repository to the underlying cache.");
-
- Assert.hasText(annotation.cacheName(), "Set a name of an Apache Ignite cache using @RepositoryConfig " +
- "annotation to map this repository to the underlying cache.");
-
- repoToCache.put(repoItf, annotation.cacheName());
-
- return super.getRepositoryMetadata(repoItf);
- }
-
- /** {@inheritDoc} */
@Override protected Object getTargetRepository(RepositoryInformation metadata) {
- return getTargetRepositoryViaReflection(metadata,
- ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+ return getTargetRepositoryViaReflection(metadata, cache);
}
/** {@inheritDoc} */
@@ -157,7 +105,7 @@
if (key != Key.CREATE && StringUtils.hasText(qryStr))
return new IgniteRepositoryQuery(metadata,
new IgniteQuery(qryStr, isFieldQuery(qryStr), IgniteQueryGenerator.getOptions(mtd)),
- mtd, factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+ mtd, factory, cache);
}
if (key == QueryLookupStrategy.Key.USE_DECLARED_QUERY)
@@ -165,7 +113,7 @@
"a query string via org.apache.ignite.springdata.repository.config.Query annotation.");
return new IgniteRepositoryQuery(metadata, IgniteQueryGenerator.generateSql(mtd, metadata), mtd,
- factory, ignite.getOrCreateCache(repoToCache.get(metadata.getRepositoryInterface())));
+ factory, cache);
}
};
}
diff --git a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
index 71200c2..3028cea 100644
--- a/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
+++ b/modules/spring-data-ext/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactoryBean.java
@@ -19,14 +19,12 @@
import java.io.Serializable;
import org.apache.ignite.Ignite;
-import org.apache.ignite.IgniteException;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.springdata.proxy.IgniteProxy;
import org.apache.ignite.springdata.repository.IgniteRepository;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
@@ -47,9 +45,10 @@
* @param <ID> Domain object key, super expects {@link Serializable}.
*/
public class IgniteRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
- extends RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
- /** Application context. */
- private ApplicationContext ctx;
+ extends RepositoryFactoryBeanSupport<T, S, ID> {
+ /** Ignite proxy. */
+ @Autowired
+ private IgniteProxy ignite;
/**
* @param repositoryInterface Repository interface.
@@ -59,50 +58,8 @@
}
/** {@inheritDoc} */
- @Override public void setApplicationContext(ApplicationContext context) throws BeansException {
- this.ctx = context;
- }
-
- /** {@inheritDoc} */
@Override protected RepositoryFactorySupport createRepositoryFactory() {
- try {
- Object igniteInstanceBean = ctx.getBean("igniteInstance");
-
- if (igniteInstanceBean instanceof Ignite)
- return new IgniteRepositoryFactory((Ignite)igniteInstanceBean);
- else if (igniteInstanceBean instanceof IgniteClient)
- return new IgniteRepositoryFactory((IgniteClient)igniteInstanceBean);
-
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to the" +
- " \"igniteInstance\" property of repository configuration must be one of the following types: " +
- Ignite.class.getName() + ", " + IgniteClient.class.getName());
- }
- catch (BeansException ex) {
- try {
- Object igniteCfgBean = ctx.getBean("igniteCfg");
-
- if (igniteCfgBean instanceof IgniteConfiguration)
- return new IgniteRepositoryFactory((IgniteConfiguration)igniteCfgBean);
- else if (igniteCfgBean instanceof ClientConfiguration)
- return new IgniteRepositoryFactory((ClientConfiguration)igniteCfgBean);
-
- throw new IllegalStateException("Invalid repository configuration. The Spring Bean corresponding to" +
- " the \"igniteCfg\" property of repository configuration must be one of the following types: [" +
- IgniteConfiguration.class.getName() + ", " + ClientConfiguration.class.getName() + ']');
- }
- catch (BeansException ex2) {
- try {
- String path = (String)ctx.getBean("igniteSpringCfgPath");
-
- return new IgniteRepositoryFactory(path);
- }
- catch (BeansException ex3) {
- throw new IgniteException("Failed to initialize Ignite repository factory. One of the following" +
- " beans must be defined in application configuration: \"igniteInstance\", \"igniteCfg\"," +
- " \"igniteSpringCfgPath\".");
- }
- }
- }
+ return new IgniteRepositoryFactory(ignite, getObjectType());
}
}
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
index a887ad8..751eb09 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteClientSpringDataCrudSelfTest.java
@@ -17,18 +17,11 @@
package org.apache.ignite.springdata;
-import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.springdata.misc.IgniteClientApplicationConfiguration;
import org.apache.ignite.springdata.misc.PersonRepository;
import org.apache.ignite.springdata.misc.PersonRepositoryWithCompoundKey;
-import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
-import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import static org.apache.ignite.springdata.compoundkey.CompoundKeyApplicationConfiguration.CLI_CONN_PORT;
/** Tests Spring Data CRUD operation when thin client is used for accessing the Ignite cluster. */
public class IgniteClientSpringDataCrudSelfTest extends IgniteSpringDataCrudSelfTest {
@@ -43,28 +36,4 @@
repoWithCompoundKey = ctx.getBean(PersonRepositoryWithCompoundKey.class);
ignite = ctx.getBean(IgniteEx.class);
}
-
- /**
- * Tests repository configuration in case {@link ClientConfiguration} is used to provide access to Ignite cluster.
- */
- @Test
- public void testRepositoryWithClientConfiguration() {
- ctx = new AnnotationConfigApplicationContext();
-
- ctx.register(TestApplicationConfiguration.class);
- ctx.refresh();
-
- assertTrue(ctx.getBean(PersonRepository.class).count() > 0);
- }
-
- /** */
- @Configuration
- @EnableIgniteRepositories("org.apache.ignite.springdata.misc")
- static class TestApplicationConfiguration {
- /** Ignite client configuration bean. */
- @Bean
- public ClientConfiguration igniteCfg() {
- return new ClientConfiguration().setAddresses("127.0.0.1:" + CLI_CONN_PORT);
- }
- }
}
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
new file mode 100644
index 0000000..aa3d6a7
--- /dev/null
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/IgniteSpringDataConnectionConfigurationTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.springdata;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.springdata.misc.Person;
+import org.apache.ignite.springdata.misc.PersonRepository;
+import org.apache.ignite.springdata.repository.IgniteRepository;
+import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
+import org.apache.ignite.springdata.repository.config.RepositoryConfig;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
+import static org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE;
+
+/** Tests Spring Data repository cluster connection configurations. */
+public class IgniteSpringDataConnectionConfigurationTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private static final String CACHE_NAME = "PersonCache";
+
+ /** */
+ private static final int CLI_CONN_PORT = 10810;
+
+ /** */
+ private static final String CLI_NAME = "cli-node";
+
+ /** */
+ private static final String SRV_NAME = "srv-node";
+
+ /** */
+ private static final String LOCAL_HOST = "127.0.0.1";
+
+ /** Tests repository configuration in case {@link IgniteConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithIgniteConfiguration() {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class);
+
+ assertClientNodeIsStopped();
+ }
+
+ /** Tests repository configuration in case {@link ClientConfiguration} is used to access the Ignite cluster. */
+ @Test
+ public void testRepositoryWithClientConfiguration() {
+ checkRepositoryConfiguration(ClientConfigurationApplication.class);
+ }
+
+ /**
+ * Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
+ * is used to access the Ignite cluster.
+ */
+ @Test
+ public void testRepositoryWithExistingIgniteInstance() throws Exception {
+ try (Ignite ignored = startGrid(getIgniteConfiguration(CLI_NAME, true))) {
+ checkRepositoryConfiguration(IgniteConfigurationApplication.class);
+
+ assertNotNull(Ignition.ignite(CLI_NAME));
+ }
+ }
+
+ /** Tests repository configuration in case specified cache name is invalid. */
+ @Test
+ public void testRepositoryWithInvalidCacheNameConfiguration() {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(InvalidCacheNameApplication.class);
+
+ assertThrowsAnyCause(log,
+ () -> {
+ ctx.refresh();
+
+ return null;
+ },
+ IllegalArgumentException.class,
+ "Invalid repository configuration [name=" + InvalidCacheRepository.class.getName() + "]. Set a" +
+ " name of an Apache Ignite cache using org.apache.ignite.springdata.repository.config.RepositoryConfig" +
+ " annotation to map this repository to the underlying cache.");
+ }
+
+ assertClientNodeIsStopped();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ grid(SRV_NAME).cache(CACHE_NAME).clear();
+ }
+
+ /** */
+ private void assertClientNodeIsStopped() {
+ assertFalse(Ignition.allGrids().stream().map(Ignite::name).anyMatch(CLI_NAME::equals));
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ startGrid(getIgniteConfiguration(SRV_NAME, false));
+ }
+
+ /**
+ * Checks that repository created based on specified Spring application configuration is properly initialized and
+ * got access to the Ignite cluster.
+ */
+ private void checkRepositoryConfiguration(Class<?> cfgCls) {
+ try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
+ ctx.register(cfgCls);
+ ctx.refresh();
+
+ PersonRepository repo = ctx.getBean(PersonRepository.class);
+
+ IgniteCache<Integer, Person> cache = grid(SRV_NAME).cache(CACHE_NAME);
+
+ assertEquals(0, repo.count());
+ assertEquals(0, cache.size());
+
+ int key = 0;
+
+ repo.save(key, new Person("Domenico", "Scarlatti"));
+
+ assertEquals(1, repo.count());
+ assertNotNull(cache.get(key));
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = PersonRepository.class))
+ public static class IgniteConfigurationApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteCfg() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link IgniteConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(
+ considerNestedRepositories = true,
+ includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = InvalidCacheRepository.class))
+ public static class InvalidCacheNameApplication {
+ /** Ignite configuration bean. */
+ @Bean
+ public IgniteConfiguration igniteCfg() {
+ return getIgniteConfiguration(CLI_NAME, true);
+ }
+ }
+
+ /**
+ * Spring Application configuration for repository testing in case {@link ClientConfiguration} is used
+ * for accessing the cluster.
+ */
+ @Configuration
+ @EnableIgniteRepositories(includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = PersonRepository.class))
+ public static class ClientConfigurationApplication {
+ /** Ignite client configuration bean. */
+ @Bean
+ public ClientConfiguration igniteCfg() {
+ return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
+ }
+ }
+
+ /** Repository for testing application behavior in case the cache name is not specified in the repository configuration. */
+ @RepositoryConfig
+ interface InvalidCacheRepository extends IgniteRepository<Person, Integer> {
+ // No-op.
+ }
+
+ /** */
+ private static IgniteConfiguration getIgniteConfiguration(String name, boolean clientMode) {
+ return new IgniteConfiguration()
+ .setIgniteInstanceName(name)
+ .setClientMode(clientMode)
+ .setLocalHost(LOCAL_HOST)
+ .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER))
+ .setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+ .setCacheConfiguration(new CacheConfiguration<>(CACHE_NAME));
+ }
+}
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
index 66379f7..5044aef 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/springdata/misc/IgniteClientApplicationConfiguration.java
@@ -25,6 +25,8 @@
import org.apache.ignite.configuration.ClientConnectorConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
import org.apache.ignite.springdata.repository.config.EnableIgniteRepositories;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -40,6 +42,7 @@
public IgniteEx igniteServerNode() {
IgniteConfiguration cfg = new IgniteConfiguration()
.setClientConnectorConfiguration(new ClientConnectorConfiguration().setPort(CLI_CONN_PORT))
+ .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(new TcpDiscoveryVmIpFinder(true)))
.setCacheConfiguration(new CacheConfiguration<Integer, Person>("PersonCache")
.setIndexedTypes(Integer.class, Person.class));
diff --git a/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java b/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
index cb6e34c..4a47568 100644
--- a/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
+++ b/modules/spring-data-ext/src/test/java/org/apache/ignite/testsuites/IgniteSpringDataTestSuite.java
@@ -21,6 +21,7 @@
import org.apache.ignite.springdata.IgniteClientSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteClientSpringDataQueriesSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataCompoundKeyTest;
+import org.apache.ignite.springdata.IgniteSpringDataConnectionConfigurationTest;
import org.apache.ignite.springdata.IgniteSpringDataCrudSelfTest;
import org.apache.ignite.springdata.IgniteSpringDataQueriesSelfTest;
import org.junit.runner.RunWith;
@@ -34,6 +35,7 @@
IgniteSpringDataCrudSelfTest.class,
IgniteSpringDataQueriesSelfTest.class,
IgniteSpringDataCompoundKeyTest.class,
+ IgniteSpringDataConnectionConfigurationTest.class,
IgniteClientSpringDataCrudSelfTest.class,
IgniteClientSpringDataQueriesSelfTest.class,
IgniteClientSpringDataCompoundKeyTest.class