Add Annotation based configuration to configure a client's 'durable-client-id' & 'durable-client-timeout' properties along with keeping the client's server event queue alive.
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.client.ClientCache;
|
||||
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 DurableClientConfiguration} class is a Spring {@link Configuration} class used to configure
|
||||
* this {@link ClientCache} instance as a {@literal Durable Client} by setting the {@literal durable-client-id}
|
||||
* and {@literal durable-client-timeout} properties in addition to enabling {@literal keepAlive}
|
||||
* on {@link ClientCache} shutdown.
|
||||
*
|
||||
* @author John Blum
|
||||
* @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.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.EnableDurableClient
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
public class DurableClientConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
|
||||
|
||||
public static final boolean DEFAULT_KEEP_ALIVE = true;
|
||||
|
||||
public static final int DEFAULT_DURABLE_CLIENT_TIMEOUT = 300;
|
||||
|
||||
private Boolean keepAlive = DEFAULT_KEEP_ALIVE;
|
||||
|
||||
private Integer durableClientTimeout = DEFAULT_DURABLE_CLIENT_TIMEOUT;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private String durableClientId;
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotationType() {
|
||||
return EnableDurableClient.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
|
||||
if (isAnnotationPresent(importMetadata)) {
|
||||
|
||||
AnnotationAttributes enableDurableClientAttributes = getAnnotationAttributes(importMetadata);
|
||||
|
||||
this.durableClientId = enableDurableClientAttributes.containsKey("id")
|
||||
? enableDurableClientAttributes.getString("id")
|
||||
: null;
|
||||
|
||||
this.durableClientTimeout = enableDurableClientAttributes.containsKey("timeout")
|
||||
? enableDurableClientAttributes.getNumber("timeout")
|
||||
: DEFAULT_DURABLE_CLIENT_TIMEOUT;
|
||||
|
||||
this.keepAlive = enableDurableClientAttributes.containsKey("keepAlive")
|
||||
? enableDurableClientAttributes.getBoolean("keepAlive")
|
||||
: DEFAULT_KEEP_ALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
protected Optional<String> getDurableClientId() {
|
||||
|
||||
return Optional.ofNullable(this.durableClientId)
|
||||
.filter(StringUtils::hasText);
|
||||
}
|
||||
|
||||
protected Integer getDurableClientTimeout() {
|
||||
|
||||
return Optional.ofNullable(this.durableClientTimeout)
|
||||
.orElse(DEFAULT_DURABLE_CLIENT_TIMEOUT);
|
||||
}
|
||||
|
||||
public Boolean getKeepAlive() {
|
||||
|
||||
return Optional.ofNullable(this.keepAlive)
|
||||
.orElse(DEFAULT_KEEP_ALIVE);
|
||||
}
|
||||
|
||||
protected Logger getLogger() {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientCacheConfigurer clientCacheDurableClientConfigurer() {
|
||||
|
||||
return (beanName, clientCacheFactoryBean) -> getDurableClientId().ifPresent(durableClientId -> {
|
||||
clientCacheFactoryBean.setDurableClientId(durableClientId);
|
||||
clientCacheFactoryBean.setDurableClientTimeout(getDurableClientTimeout());
|
||||
clientCacheFactoryBean.setKeepAlive(getKeepAlive());
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
PeerCacheConfigurer peerCacheDurableClientConfigurer() {
|
||||
|
||||
return (beanName, cacheFactoryBean) -> getDurableClientId().ifPresent(durableClientId -> {
|
||||
|
||||
Logger logger = getLogger();
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Durable Client ID [{}] was set on a peer Cache instance, which will not have any effect",
|
||||
durableClientId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.client.ClientCache;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The {@link EnableDurableClient} annotation configures a {@link ClientCache} instance as a {@literal Durable Client}.
|
||||
*
|
||||
* @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.client.ClientCache
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.geode.config.annotation.DurableClientConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Import(DurableClientConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public @interface EnableDurableClient {
|
||||
|
||||
/**
|
||||
* Used only for clients in a client/server installation. If set, this indicates that the client is durable
|
||||
* and identifies the client. The ID is used by servers to reestablish any messaging that was interrupted
|
||||
* by client downtime.
|
||||
*/
|
||||
String id();
|
||||
|
||||
/**
|
||||
* Configure whether the server should keep the durable client's queues alive for the timeout period.
|
||||
*
|
||||
* Defaults to {@literal true}.
|
||||
*/
|
||||
boolean keepAlive() default DurableClientConfiguration.DEFAULT_KEEP_ALIVE;
|
||||
|
||||
/**
|
||||
* Used only for clients in a client/server installation. Number of seconds this client can remain disconnected
|
||||
* from its server and have the server continue to accumulate durable events for it.
|
||||
*
|
||||
* Defaults to {@literal 300 seconds}, or {@literal 5 minutes}.
|
||||
*/
|
||||
int timeout() default DurableClientConfiguration.DEFAULT_DURABLE_CLIENT_TIMEOUT;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
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 EnableDurableClient} and {@link DurableClientConfiguration}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
|
||||
* @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.geode.config.annotation.DurableClientConfiguration
|
||||
* @see org.springframework.geode.config.annotation.EnableDurableClient
|
||||
* @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 DurableClientIdConfigurationIntegrationTests extends IntegrationTestsSupport {
|
||||
|
||||
private static final AtomicReference<ConfigurableApplicationContext> applicationContextReference =
|
||||
new AtomicReference<>(null);
|
||||
|
||||
private static final AtomicReference<ClientCache> clientCacheReference =
|
||||
new AtomicReference<>(null);
|
||||
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private GemFireCache gemfireCache;
|
||||
|
||||
@Autowired
|
||||
private ClientCacheFactoryBean clientCacheFactoryBean;
|
||||
|
||||
@AfterClass
|
||||
public static void closeApplicationContext() {
|
||||
|
||||
Optional.ofNullable(applicationContextReference.get()).ifPresent(ConfigurableApplicationContext::close);
|
||||
|
||||
ClientCache clientCache = clientCacheReference.get();
|
||||
|
||||
assertThat(clientCache).isNotNull();
|
||||
|
||||
verify(clientCache, times(1)).close(eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void durableClientWasConfiguredSuccessfully() {
|
||||
|
||||
assertThat(this.gemfireCache).isInstanceOf(ClientCache.class);
|
||||
assertThat(this.gemfireCache.getDistributedSystem()).isNotNull();
|
||||
assertThat(this.gemfireCache.getDistributedSystem().getProperties()).isNotNull();
|
||||
assertThat(this.gemfireCache.getDistributedSystem().getProperties().getProperty("durable-client-id"))
|
||||
.isEqualTo("abc123");
|
||||
assertThat(this.gemfireCache.getDistributedSystem().getProperties().getProperty("durable-client-timeout"))
|
||||
.isEqualTo("600");
|
||||
|
||||
applicationContextReference.set(this.applicationContext);
|
||||
clientCacheReference.set((ClientCache) this.gemfireCache);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setClientCacheFactoryBeanSetsKeepAliveOnClose() {
|
||||
|
||||
assertThat(this.clientCacheFactoryBean).isNotNull();
|
||||
assertThat(this.clientCacheFactoryBean.isKeepAlive()).isTrue();
|
||||
}
|
||||
|
||||
@ClientCacheApplication
|
||||
@EnableGemFireMockObjects
|
||||
@EnableDurableClient(id = "abc123", timeout = 600)
|
||||
static class TestConfiguration { }
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user