Skip to content
Permalink
Browse files
IGNITE-13169 Remove Ignite bean name requirement for Spring Data Repo…
…sitory - Fixes #55.

Signed-off-by: Sergey Chugunov <sergey.chugunov@gmail.com>
  • Loading branch information
SammyVimes authored and sergey-chugunov-1985 committed Apr 16, 2021
1 parent c8de80e commit a25117b7ce4c156bf29d207e43002d35b9ff70cc
Showing 9 changed files with 433 additions and 71 deletions.
@@ -29,10 +29,10 @@
/**
* Every {@link IgniteRepository} is bound to a specific Apache Ignite that it communicates to in order to mutate and
* read data via Spring Data API. To pass an instance of Apache Ignite cache to an {@link IgniteRepository} it's
* required to initialize {@link IgniteRepositoryFactoryBean} with on of the following:
* required to initialize {@link IgniteRepositoryFactoryBean} with one of the following:
* <ul>
* <li>{@link Ignite} instance bean named "igniteInstance"</li>
* <li>{@link IgniteConfiguration} bean named "igniteCfg"</li>
* <li>{@link Ignite} instance bean</li>
* <li>{@link IgniteConfiguration} bean</li>
* <li>A path to Ignite's Spring XML configuration named "igniteSpringCfgPath"</li>
* <ul/>
* In this example the first approach is utilized.
@@ -19,8 +19,14 @@

import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.ignite.Ignite;
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.springdata20.repository.config.RepositoryConfig;
import org.springframework.beans.BeansException;
@@ -103,29 +109,25 @@ public IgniteProxy igniteProxy(Class<?> repoInterface) {
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);
return Stream.<BeanFinder>of(
() -> ctx.getBean(evaluateExpression(repoCfg.igniteInstance())),
() -> ctx.getBean(evaluateExpression(repoCfg.igniteCfg())),
() -> ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class),
() -> ctx.getBean(Ignite.class),
() -> ctx.getBean(IgniteClient.class),
() -> ctx.getBean(IgniteConfiguration.class),
() -> ctx.getBean(ClientConfiguration.class)
).map(BeanFinder::getBean)
.filter(Objects::nonNull)
.findFirst()
.map(IgniteProxy::of)
.orElseThrow(() -> {
return 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 or provide Ignite, IgniteClient, " +
" ClientConfiguration or IgniteConfiguration bean to application context.");
});
}

/**
@@ -137,4 +139,29 @@ private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
private String evaluateExpression(String spelExpression) {
return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
}

/**
* Helper interface that wraps getBean method.
*/
@FunctionalInterface
private interface BeanFinder {
/**
* Get bean.
* @return Bean or null if {@link BeansException} was thrown.
*/
default Object getBean() {
try {
return get();
} catch (BeansException ex) {
return null;
}
}

/**
* Get bean.
* @return Bean.
* @throws BeansException If bean was not found.
*/
Object get() throws BeansException;
}
}
@@ -34,8 +34,8 @@
* The {@link org.apache.ignite.springdata20.repository.config.RepositoryConfig} requires to define one of the
* parameters below in your Spring application configuration in order to get an access to Apache Ignite cluster:
* <ul>
* <li>{@link Ignite} instance bean named "igniteInstance" by default</li>
* <li>{@link IgniteConfiguration} bean named "igniteCfg" by default</li>
* <li>{@link Ignite} instance bean</li>
* <li>{@link IgniteConfiguration} bean</li>
* <li>A path to Ignite's Spring XML configuration named "igniteSpringCfgPath" by default</li>
* <ul/>
*
@@ -21,6 +21,7 @@
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.configuration.ClientConnectorConfiguration;
@@ -75,6 +76,30 @@ public void testRepositoryWithClientConfiguration() {
checkRepositoryConfiguration(ClientConfigurationApplication.class, IgniteClientConfigRepository.class);
}

/** Tests repository configuration in case {@link Ignite} with non default is used to access the Ignite cluster. */
@Test
public void testRepositoryWithoutIgniteInstanceParameter() {
checkRepositoryConfiguration(DefaultIgniteBeanApplication.class, IgniteRepositoryWithoutExplicitIgnite.class);
}

/** Tests repository configuration in case {@link IgniteClient} with non default name is used to access the Ignite cluster. */
@Test
public void testRepositoryWithoutIgniteClientInstanceParameter() {
checkRepositoryConfiguration(DefaultIgniteClientBeanApplication.class, IgniteRepositoryWithoutExplicitIgnite.class);
}

/** Tests repository configuration in case {@link ClientConfiguration} with non default name is used to access the Ignite cluster. */
@Test
public void testRepositoryWithoutIgnitClientConfigurationParameter() {
checkRepositoryConfiguration(DefaultIgniteClientConfigurationBeanApplication.class, IgniteRepositoryWithoutExplicitIgnite.class);
}

/** Tests repository configuration in case {@link IgniteConfiguration} with non default name is used to access the Ignite cluster. */
@Test
public void testRepositoryWithoutIgniteConfigurationParameter() {
checkRepositoryConfiguration(DefaultIgniteConfigurationBeanApplication.class, IgniteRepositoryWithoutExplicitIgnite.class);
}

/**
* Tests repository configuration in case {@link IgniteConfiguration} that refers to existing Ignite node instance
* used to access the Ignite cluster.
@@ -205,6 +230,80 @@ public ClientConfiguration clientConfiguration() {
}
}

/**
* Spring Application configuration for repository testing in case if Ignite bean name was not provided
* through {@link RepositoryConfig#igniteInstance()} ()}.
*/
@Configuration
@EnableIgniteRepositories(
considerNestedRepositories = true,
includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteRepositoryWithoutExplicitIgnite.class)
)
public static class DefaultIgniteBeanApplication {
/** Ignite bean. */
@Bean
public Ignite someIgnite() {
return Ignition.start(getIgniteConfiguration("test", false));
}
}

/**
* Spring Application configuration for repository testing in case if IgniteClient bean name was not provided
* through {@link RepositoryConfig#igniteInstance()} ()}.
*/
@Configuration
@EnableIgniteRepositories(
considerNestedRepositories = true,
includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteRepositoryWithoutExplicitIgnite.class)
)
public static class DefaultIgniteClientBeanApplication {
/** Ignite client bean. */
@Bean
public IgniteClient someIgnite() {
return Ignition.startClient(new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT));
}
}

/**
* Spring Application configuration for repository testing in case if ClientConfiguration bean name was not provided
* through {@link RepositoryConfig#igniteCfg()}.
*/
@Configuration
@EnableIgniteRepositories(
considerNestedRepositories = true,
includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteRepositoryWithoutExplicitIgnite.class)
)
public static class DefaultIgniteClientConfigurationBeanApplication {
/** Ignite client configuration bean. */
@Bean
public ClientConfiguration someCfg() {
return new ClientConfiguration().setAddresses(LOCAL_HOST + ':' + CLI_CONN_PORT);
}
}

/**
* Spring Application configuration for repository testing in case if IgniteConfiguration bean name was not provided
* through {@link RepositoryConfig#igniteCfg()}.
*/
@Configuration
@EnableIgniteRepositories(
considerNestedRepositories = true,
includeFilters = @Filter(type = ASSIGNABLE_TYPE, classes = IgniteRepositoryWithoutExplicitIgnite.class)
)
public static class DefaultIgniteConfigurationBeanApplication {
/** Ignite client configuration bean. */
@Bean
public IgniteConfiguration someCfg() {
return getIgniteConfiguration("test", false);
}
}

/** Repository for testing configuration approach through default ignite beans. */
@RepositoryConfig(cacheName = "PersonCache")
public interface IgniteRepositoryWithoutExplicitIgnite extends IgniteRepository<Object, Serializable> {
// No-op.
}

/** Repository for testing configuration approach through {@link IgniteConfiguration}. */
@RepositoryConfig(cacheName = "PersonCache", igniteCfg = "igniteConfiguration")
public interface IgniteConfigRepository extends IgniteRepository<Object, Serializable> {
@@ -19,8 +19,14 @@

import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.apache.ignite.Ignite;
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.springdata22.repository.config.RepositoryConfig;
import org.springframework.beans.BeansException;
@@ -103,29 +109,25 @@ public IgniteProxy igniteProxy(Class<?> repoInterface) {
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);
return Stream.<BeanFinder>of(
() -> ctx.getBean(evaluateExpression(repoCfg.igniteInstance())),
() -> ctx.getBean(evaluateExpression(repoCfg.igniteCfg())),
() -> ctx.getBean(evaluateExpression(repoCfg.igniteSpringCfgPath()), String.class),
() -> ctx.getBean(Ignite.class),
() -> ctx.getBean(IgniteClient.class),
() -> ctx.getBean(IgniteConfiguration.class),
() -> ctx.getBean(ClientConfiguration.class)
).map(BeanFinder::getBean)
.filter(Objects::nonNull)
.findFirst()
.map(IgniteProxy::of)
.orElseThrow(() -> {
return 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 or provide Ignite, IgniteClient, " +
" ClientConfiguration or IgniteConfiguration bean to application context.");
});
}

/**
@@ -137,4 +139,29 @@ private IgniteProxy createIgniteProxy(Class<?> repoInterface) {
private String evaluateExpression(String spelExpression) {
return (String)expressionResolver.evaluate(spelExpression, beanExpressionCtx);
}

/**
* Helper interface that wraps getBean method.
*/
@FunctionalInterface
private interface BeanFinder {
/**
* Get bean.
* @return Bean or null if {@link BeansException} was thrown.
*/
default Object getBean() {
try {
return get();
} catch (BeansException ex) {
return null;
}
}

/**
* Get bean.
* @return Bean.
* @throws BeansException If bean was not found.
*/
Object get() throws BeansException;
}
}
@@ -34,8 +34,8 @@
* The {@link org.apache.ignite.springdata22.repository.config.RepositoryConfig} requires to define one of the
* parameters below in your Spring application configuration in order to get an access to Apache Ignite cluster:
* <ul>
* <li>{@link Ignite} instance bean named "igniteInstance" by default</li>
* <li>{@link IgniteConfiguration} bean named "igniteCfg" by default</li>
* <li>{@link Ignite} instance bean</li>
* <li>{@link IgniteConfiguration} bean</li>
* <li>A path to Ignite's Spring XML configuration named "igniteSpringCfgPath" by default</li>
* <ul/>
*

0 comments on commit a25117b

Please sign in to comment.