diff --git a/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/GroupsConfiguration.java b/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/GroupsConfiguration.java new file mode 100644 index 00000000..35efd8fe --- /dev/null +++ b/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/GroupsConfiguration.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.springframework.geode.config.annotation; + +import java.lang.annotation.Annotation; +import java.util.Optional; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.client.ClientCache; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportAware; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer; +import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; +import org.springframework.util.StringUtils; + +/** + * The {@link GroupsConfiguration} class is a Spring {@link Configuration} class used to configure the {@literal groups} + * in which is member belongs in an Apache Geode/Pivotal GemFire distributed system, whether the member + * is a {@link ClientCache} in a client/server topology or a {@link Cache peer Cache} in a cluster + * using the P2P topology. + * + * @author John Blum + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.context.annotation.ImportAware + * @see org.springframework.core.annotation.AnnotationAttributes + * @see org.springframework.core.type.AnnotationMetadata + * @see org.springframework.data.gemfire.CacheFactoryBean + * @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer + * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport + * @see org.springframework.geode.config.annotation.UseGroups + * @since 1.0.0 + */ +@Configuration +@SuppressWarnings("unused") +public class GroupsConfiguration extends AbstractAnnotationConfigSupport implements ImportAware { + + private static final String GEMFIRE_GROUPS_PROPERTY = "groups"; + + private String[] groups = {}; + + @Override + protected Class getAnnotationType() { + return UseGroups.class; + } + + @Override + public void setImportMetadata(AnnotationMetadata importMetadata) { + + if (isAnnotationPresent(importMetadata)) { + + AnnotationAttributes inGroupsAttributes = getAnnotationAttributes(importMetadata); + + setGroups(inGroupsAttributes.containsKey("value") + ? inGroupsAttributes.getStringArray("value") : null); + + setGroups(inGroupsAttributes.containsKey("groups") + ? inGroupsAttributes.getStringArray("groups") : null); + } + } + + protected void setGroups(String[] groups) { + + this.groups = Optional.ofNullable(groups) + .filter(it -> it.length > 0) + .orElse(this.groups); + } + + protected Optional getGroups() { + + return Optional.ofNullable(this.groups) + .filter(it -> it.length > 0); + } + + @Bean + ClientCacheConfigurer clientCacheGroupsConfigurer() { + return (beaName, clientCacheFactoryBean) -> configureGroups(clientCacheFactoryBean); + } + + @Bean + PeerCacheConfigurer peerCacheGroupsConfigurer() { + return (beaName, peerCacheFactoryBean) -> configureGroups(peerCacheFactoryBean); + } + + private void configureGroups(CacheFactoryBean cacheFactoryBean) { + getGroups().ifPresent(groups -> cacheFactoryBean.getProperties() + .setProperty(GEMFIRE_GROUPS_PROPERTY, StringUtils.arrayToCommaDelimitedString(groups))); + } +} diff --git a/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/UseGroups.java b/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/UseGroups.java new file mode 100644 index 00000000..67f171af --- /dev/null +++ b/geode-spring-boot/src/main/java/org/springframework/geode/config/annotation/UseGroups.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.springframework.geode.config.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.client.ClientCache; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.AliasFor; + +/** + * The {@link UseGroups} annotation configures the groups in which the member belongs in an Apache Geode + * or Pivotal GemFire distributed system, whether the member is a {@link ClientCache} in a client/server topology + * or a {@link Cache peer Cache} in a cluster using the P2P topology. + * + * @author John Blum + * @see java.lang.annotation.Documented + * @see java.lang.annotation.Inherited + * @see java.lang.annotation.Retention + * @see java.lang.annotation.Target + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.context.annotation.Import + * @see org.springframework.core.annotation.AliasFor + * @see org.springframework.geode.config.annotation.GroupsConfiguration + * @since 1.0.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Import(GroupsConfiguration.class) +@SuppressWarnings("unused") +public @interface UseGroups { + + @AliasFor("groups") + String[] value() default {}; + + @AliasFor("value") + String[] groups() default {}; + +} diff --git a/geode-spring-boot/src/test/java/org/springframework/geode/config/annotation/GroupsConfigurationIntegrationTests.java b/geode-spring-boot/src/test/java/org/springframework/geode/config/annotation/GroupsConfigurationIntegrationTests.java new file mode 100644 index 00000000..9ac075ab --- /dev/null +++ b/geode-spring-boot/src/test/java/org/springframework/geode/config/annotation/GroupsConfigurationIntegrationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.springframework.geode.config.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.geode.cache.GemFireCache; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.gemfire.config.annotation.ClientCacheApplication; +import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport; +import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests for {@link UseGroups} and {@link GroupsConfiguration}. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication + * @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport + * @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 1.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class GroupsConfigurationIntegrationTests extends IntegrationTestsSupport { + + @Autowired + private GemFireCache gemfireCache; + + @Test + public void groupsAreConfiguredCorrectly() { + + assertThat(this.gemfireCache).isNotNull(); + assertThat(this.gemfireCache.getDistributedSystem()).isNotNull(); + assertThat(this.gemfireCache.getDistributedSystem().getProperties()).isNotNull(); + assertThat(this.gemfireCache.getDistributedSystem().getProperties().getProperty("groups")) + .isEqualTo("MockGroup,TestGroup"); + + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @UseGroups({ "MockGroup", "TestGroup" }) + static class TestConfiguration { } + +}