Add annotation configuration support to configure Apache Geode/Pivotal GemFire Locators ('locators') used in P2P topologies and remote Locators ('remote-locators') used in WAN topologies.

This commit is contained in:
John Blum
2018-06-21 17:51:42 -07:00
parent ebca814c74
commit d98c8d1334
3 changed files with 354 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
/*
* 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 java.util.Properties;
import org.apache.geode.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.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 LocatorsConfiguration} class is a Spring {@link Configuration} class used to configure Apache Geode
* or Pivotal GemFire's {@literal locators} and/or {@literal remote-locators} properties used by a
* {@link Cache peer Cache member} to join a cluster of servers when using the P2P topology.
*
* The {@literal remote-locators} property is used to configure the Locators that a cluster will use in order to
* connect to a remote site in a multi-site (WAN) topology configuration. To use Locators in a WAN configuration,
* you must specify a unique distributed system ID ({@literal distributed-system-id}) for the local cluster
* and remote Locator(s) for the remote clusters to which you will connect.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @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.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.geode.config.annotation.UseLocators
* @since 1.0.0
*/
@Configuration
@SuppressWarnings("unused")
public class LocatorsConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
protected static final String DEFAULT_LOCATORS = "localhost[10334]";
protected static final String DEFAULT_REMOTE_LOCATORS = "";
protected static final String LOCATORS_PROPERTY = "locators";
protected static final String REMOTE_LOCATORS_PROPERTY = "remote-locators";
private final Logger logger = LoggerFactory.getLogger(getClass());
private String locators;
private String remoteLocators;
@Override
protected Class<? extends Annotation> getAnnotationType() {
return UseLocators.class;
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (isAnnotationPresent(importMetadata)) {
AnnotationAttributes useLocatorsAttributes = getAnnotationAttributes(importMetadata);
setLocators(useLocatorsAttributes.containsKey("locators")
? useLocatorsAttributes.getString("locators") : null);
setRemoteLocators(useLocatorsAttributes.containsKey("remoteLocators")
? useLocatorsAttributes.getString("remoteLocators") : null);
}
}
protected void setLocators(String locators) {
this.locators = StringUtils.hasText(locators) ? locators : null;
}
protected Optional<String> getLocators() {
return Optional.ofNullable(this.locators)
.filter(StringUtils::hasText);
}
protected Logger getLogger() {
return this.logger;
}
protected void setRemoteLocators(String remoteLocators) {
this.remoteLocators = StringUtils.hasText(remoteLocators) ? remoteLocators : null;
}
protected Optional<String> getRemoteLocators() {
return Optional.ofNullable(this.remoteLocators)
.filter(StringUtils::hasText);
}
@Bean
ClientCacheConfigurer clientCacheLocatorsConfigurer() {
return (beanName, clientCacheFactoryBean) -> {
Logger logger = getLogger();
getLocators().ifPresent(locators -> {
if (logger.isWarnEnabled()) {
logger.warn("The '%s' property was configured [%s];"
+ " however, this value does not have any effect for ClientCache instances",
LOCATORS_PROPERTY, locators);
}
});
getRemoteLocators().ifPresent(remoteLocators -> {
if (logger.isWarnEnabled()) {
logger.warn("The '%s' property was configured [%s];"
+ " however, this value does not have any effect for ClientCache instances",
REMOTE_LOCATORS_PROPERTY, remoteLocators);
}
});
};
}
@Bean
PeerCacheConfigurer peerCacheLocatorsConfigurer() {
return (beanName, cacheFactoryBean) -> {
Properties gemfireProperties = cacheFactoryBean.getProperties();
getLocators().ifPresent(locators -> gemfireProperties.setProperty(LOCATORS_PROPERTY, locators));
getRemoteLocators().ifPresent(remoteLocators ->
gemfireProperties.setProperty(REMOTE_LOCATORS_PROPERTY, remoteLocators));
};
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.springframework.geode.config.annotation.LocatorsConfiguration.DEFAULT_LOCATORS;
import static org.springframework.geode.config.annotation.LocatorsConfiguration.DEFAULT_REMOTE_LOCATORS;
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.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link UseLocators} annotation configures the {@literal locators} and/or {@literal remote-locators}
* Apache Geode/Pivotal GemFire properties used by a {@link Cache peer Cache member} to join a cluster of servers
* when using the P2P topology as well as when configuring the multi-site, WAN 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.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.geode.config.annotation.MemberNameConfiguration
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(LocatorsConfiguration.class)
@SuppressWarnings("unused")
public @interface UseLocators {
/**
* @see #locators()
*/
@AliasFor("locators")
String value() default DEFAULT_LOCATORS;
/**
* The list of Locators used by system members. The list must be configured consistently for every member of
* the cluster (a.k.a. distributed system). If the list is empty, Locators will not be used.
*
* For each Locator, provide a hostname and/or address (separated by @, if you use both), followed by
* a port number in brackets.
*
* For example:
*
* <code>
* locators=address1[port1],address2[port2],...,addressN[portN]
* locators=hostname1@address1[port1],hostname2@address2[port2],...,hostnameN@addressN[portN]
* locators=hostname1[port1],hostname2[port2],...,hostnameN[portN]
* </code>
*
* Defaults to {@literal localhost[10334]}.
*/
@AliasFor("value")
String locators() default DEFAULT_LOCATORS;
/**
* Used to configure the Locators that a cluster will use in order to connect to a remote site in a multi-site
* (WAN) topology configuration.
*
* To use Locators in a WAN configuration, you must specify a unique distributed system ID ({@literal distributed-system-id})
* for the local cluster and remote Locator(s) for the remote clusters to which you will connect.
*
* For each remote Locator, provide a host name and/or address (separated by @, if you use both), followed by
* a port number in brackets.
*
* For example:
*
* <code>
* remote-locators=address1[port1],address2[port2],...,addressN[portN]
* remote-locators=hostname1@address1[port1],hostname2@address2[port2],...,hostnameN@addressN[portN]
* remote-locators=hostname1[port1],hostname2[port2],...,hostnameN[portN]
* </code>
*
* Defaults to unset.
*/
String remoteLocators() default DEFAULT_REMOTE_LOCATORS;
}