diff --git a/pom.xml b/pom.xml
index 60129278..0dff2327 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,34 @@
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ ${checkstyle.version}
+
+
+ org.springframework.cloud
+ spring-cloud-build-tools
+ ${spring-cloud-build.version}
+
+
+
+
+ validate
+ validate
+
+ checkstyle.xml
+ LICENSE.txt
+ true
+ true
+
+
+ check
+
+
+
+
+
@@ -132,6 +160,8 @@
1.0-groovy-2.4
+ 2.17
+ 1.1.0.BUILD-SNAPSHOT
diff --git a/spring-cloud-zookeeper-config/pom.xml b/spring-cloud-zookeeper-config/pom.xml
index 1b5462f2..92d15741 100644
--- a/spring-cloud-zookeeper-config/pom.xml
+++ b/spring-cloud-zookeeper-config/pom.xml
@@ -40,6 +40,11 @@
spring-boot-starter-web
true
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+ true
+
org.apache.curator
curator-recipes
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ConfigWatcher.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ConfigWatcher.java
new file mode 100644
index 00000000..a362c43a
--- /dev/null
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ConfigWatcher.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013-2016 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.cloud.zookeeper.config;
+
+import java.io.Closeable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.PostConstruct;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.recipes.cache.TreeCache;
+import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
+import org.apache.curator.framework.recipes.cache.TreeCacheListener;
+import org.apache.zookeeper.KeeperException;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+
+import lombok.extern.apachecommons.CommonsLog;
+
+import static org.apache.curator.framework.recipes.cache.TreeCacheEvent.Type.NODE_ADDED;
+import static org.apache.curator.framework.recipes.cache.TreeCacheEvent.Type.NODE_REMOVED;
+import static org.apache.curator.framework.recipes.cache.TreeCacheEvent.Type.NODE_UPDATED;
+
+/**
+ * @author Spencer Gibb
+ */
+@CommonsLog
+public class ConfigWatcher implements Closeable, TreeCacheListener, ApplicationEventPublisherAware{
+
+ private AtomicBoolean running = new AtomicBoolean(false);
+ private List contexts;
+ private CuratorFramework source;
+ private ApplicationEventPublisher publisher;
+ private HashMap caches;
+
+ public ConfigWatcher(List contexts, CuratorFramework source) {
+ this.contexts = contexts;
+ this.source = source;
+ }
+
+ @Override
+ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
+ this.publisher = publisher;
+ }
+
+ @PostConstruct
+ public void start() {
+ if (this.running.compareAndSet(false, true)) {
+ this.caches = new HashMap<>();
+ for (String context : contexts) {
+ if (!context.startsWith("/")) {
+ context = "/" + context;
+ }
+
+ try {
+ TreeCache cache = TreeCache.newBuilder(this.source, context).build();
+ cache.getListenable().addListener(this);
+ cache.start();
+ this.caches.put(context, cache);
+ // no race condition since ZookeeperAutoConfiguration.curatorFramework
+ // calls curator.blockUntilConnected
+ } catch (KeeperException.NoNodeException e) {
+ // no node, ignore
+ } catch (Exception e) {
+ log.error("Error initializing listener for context " + context, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ if (this.running.compareAndSet(true, false)) {
+ for (TreeCache cache : this.caches.values()) {
+ cache.close();
+ }
+ this.caches = null;
+ }
+ }
+
+ @Override
+ public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
+ TreeCacheEvent.Type eventType = event.getType();
+ if (eventType == NODE_ADDED || eventType == NODE_REMOVED || eventType == NODE_UPDATED) {
+ this.publisher.publishEvent(new ZookeeperConfigRefreshEvent(this, event));
+ }
+ }
+}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigAutoConfiguration.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigAutoConfiguration.java
new file mode 100644
index 00000000..372f9b1b
--- /dev/null
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigAutoConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013-2016 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.cloud.zookeeper.config;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.endpoint.RefreshEndpoint;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Spencer Gibb
+ */
+@Configuration
+public class ZookeeperConfigAutoConfiguration {
+
+ @Configuration
+ @ConditionalOnClass(RefreshEndpoint.class)
+ protected static class ZkRefreshConfiguration {
+ @Bean
+ @ConditionalOnBean(RefreshEndpoint.class)
+ public ZookeeperConfigRefreshListener zookeeperConfigRefreshListener(
+ RefreshEndpoint refreshEndpoint) {
+ return new ZookeeperConfigRefreshListener(refreshEndpoint);
+ }
+
+ @Bean
+ @ConditionalOnProperty(name = "spring.cloud.zookeeper.config.watcher.enabled", matchIfMissing = true)
+ public ConfigWatcher configWatcher(ZookeeperPropertySourceLocator locator,
+ CuratorFramework curator) {
+ return new ConfigWatcher(locator.getContexts(), curator);
+ }
+ }
+}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigProperties.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigProperties.java
index c1744c72..f29cff66 100644
--- a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigProperties.java
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigProperties.java
@@ -36,6 +36,4 @@ public class ZookeeperConfigProperties {
@NotEmpty
private String profileSeparator = ",";
-
- private boolean cacheEnabled = true;
}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshEvent.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshEvent.java
new file mode 100644
index 00000000..b99a0e39
--- /dev/null
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013-2016 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.cloud.zookeeper.config;
+
+import java.nio.charset.Charset;
+
+import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * @author Spencer Gibb
+ */
+public class ZookeeperConfigRefreshEvent extends ApplicationEvent {
+
+ private TreeCacheEvent event;
+
+ /**
+ * Create a new ApplicationEvent.
+ *
+ * @param source the object on which the event initially occurred (never {@code null})
+ */
+ public ZookeeperConfigRefreshEvent(Object source, TreeCacheEvent event) {
+ super(source);
+ this.event = event;
+ }
+
+ public TreeCacheEvent getEvent() {
+ return event;
+ }
+
+ public String getEventDesc() {
+ StringBuffer out = new StringBuffer();
+ out.append("type="+event.getType());
+ out.append(", path="+event.getData().getPath());
+ byte[] data = event.getData().getData();
+ if (data != null && data.length > 0) {
+ out.append(", data="+new String(data, Charset.forName("UTF-8")));
+ }
+ return out.toString();
+ }
+}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshListener.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshListener.java
new file mode 100644
index 00000000..108b1c8d
--- /dev/null
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigRefreshListener.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013-2016 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.cloud.zookeeper.config;
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.cloud.endpoint.RefreshEndpoint;
+import org.springframework.context.event.EventListener;
+
+import lombok.extern.apachecommons.CommonsLog;
+
+/**
+ * @author Spencer Gibb
+ */
+@CommonsLog
+public class ZookeeperConfigRefreshListener {
+ private RefreshEndpoint refresh;
+ private AtomicBoolean ready = new AtomicBoolean(false);
+
+ public ZookeeperConfigRefreshListener(RefreshEndpoint refresh) {
+ this.refresh = refresh;
+ }
+
+ @EventListener
+ public void handle(ApplicationReadyEvent event) {
+ this.ready.compareAndSet(false, true);
+ }
+
+ @EventListener
+ public void handle(ZookeeperConfigRefreshEvent event) {
+ if (this.ready.get()) { // don't handle events before app is ready
+ log.debug("Event received " + event.getEventDesc());
+ if (this.refresh != null) {
+ String[] keys = this.refresh.refresh();
+ log.info("Refresh keys changed: " + Arrays.asList(keys));
+ }
+ }
+ }
+}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocator.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocator.java
index f20aa29a..9c5ca49b 100644
--- a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocator.java
+++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocator.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PreDestroy;
@@ -40,13 +39,17 @@ public class ZookeeperPropertySourceLocator implements PropertySourceLocator {
private CuratorFramework curator;
- private ConcurrentHashMap lifecycleSources = new ConcurrentHashMap<>();
+ private List contexts;
public ZookeeperPropertySourceLocator(CuratorFramework curator, ZookeeperConfigProperties properties) {
this.curator = curator;
this.properties = properties;
}
+ public List getContexts() {
+ return contexts;
+ }
+
@Override
public PropertySource> locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
@@ -55,7 +58,7 @@ public class ZookeeperPropertySourceLocator implements PropertySourceLocator {
List profiles = Arrays.asList(env.getActiveProfiles());
String root = properties.getRoot();
- List contexts = new ArrayList<>();
+ contexts = new ArrayList<>();
String defaultContext = root + "/" + properties.getDefaultContext();
contexts.add(defaultContext);
@@ -82,18 +85,9 @@ public class ZookeeperPropertySourceLocator implements PropertySourceLocator {
@PreDestroy
public void destroy() {
- for (ZookeeperTreeCachePropertySource source : this.lifecycleSources.values()) {
- source.stop();
- }
}
private PropertySource create(String context) {
- if (this.properties.isCacheEnabled()) {
- ZookeeperTreeCachePropertySource propertySource = new ZookeeperTreeCachePropertySource(context, curator);
- propertySource.start();
- lifecycleSources.put(propertySource.getName(), propertySource);
- return propertySource;
- }
return new ZookeeperPropertySource(context, curator);
}
diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperTreeCachePropertySource.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperTreeCachePropertySource.java
deleted file mode 100644
index 54f6c896..00000000
--- a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperTreeCachePropertySource.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2013-2015 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.cloud.zookeeper.config;
-
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import lombok.extern.apachecommons.CommonsLog;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.recipes.cache.ChildData;
-import org.apache.curator.framework.recipes.cache.TreeCache;
-import org.apache.zookeeper.KeeperException.NoNodeException;
-import org.springframework.context.Lifecycle;
-
-/**
- * @author Spencer Gibb
- */
-@CommonsLog
-public class ZookeeperTreeCachePropertySource extends AbstractZookeeperPropertySource
- implements Lifecycle {
-
- private TreeCache cache;
- private boolean running;
-
- public ZookeeperTreeCachePropertySource(String context, CuratorFramework source) {
- super(context, source);
- }
-
- @Override
- public void start() {
- try {
- cache = TreeCache.newBuilder(source, this.getContext()).build();
- cache.start();
- running = true;
- // no race condition since ZookeeperAutoConfiguration.curatorFramework
- // calls curator.blockUntilConnected
- }
- catch (NoNodeException e) {
- // no node, ignore
- }
- catch (Exception e) {
- log.error("Error initializing ZookeperPropertySource", e);
- }
- }
-
- @Override
- public Object getProperty(String name) {
- String fullPath = this.getContext() + "/" + name.replace(".", "/");
- byte[] bytes = null;
- ChildData data = cache.getCurrentData(fullPath);
- if (data != null) {
- bytes = data.getData();
- }
- if (bytes == null)
- return null;
- return new String(bytes, Charset.forName("UTF-8"));
- }
-
- @Override
- public String[] getPropertyNames() {
- List keys = new ArrayList<>();
- findKeys(keys, this.getContext());
- return keys.toArray(new String[0]);
- }
-
- protected void findKeys(List keys, String path) {
- log.trace("enter findKeysCached for path: " + path);
- Map children = cache.getCurrentChildren(path);
-
- if (children == null)
- return;
- for (Map.Entry entry : children.entrySet()) {
- ChildData child = entry.getValue();
- if (child.getData() == null || child.getData().length == 0) {
- findKeys(keys, child.getPath());
- }
- else {
- keys.add(sanitizeKey(child.getPath()));
- }
- }
- log.trace("leaving findKeysCached for path: " + path);
- }
-
-
- @Override
- public void stop() {
- cache.close();
- running = false;
- }
-
- @Override
- public boolean isRunning() {
- return running;
- }
-
-}
diff --git a/spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories b/spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories
index d1701df5..f9be33b4 100644
--- a/spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories
@@ -1,3 +1,7 @@
+# Auto Configuration
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springframework.cloud.zookeeper.config.ZookeeperConfigAutoConfiguration
+
# Bootstrap Configuration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.zookeeper.config.ZookeeperConfigBootstrapConfiguration
diff --git a/spring-cloud-zookeeper-config/src/test/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocatorTests.java b/spring-cloud-zookeeper-config/src/test/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocatorTests.java
index ce4fe939..50a80a28 100644
--- a/spring-cloud-zookeeper-config/src/test/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocatorTests.java
+++ b/spring-cloud-zookeeper-config/src/test/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocatorTests.java
@@ -16,25 +16,34 @@
package org.springframework.cloud.zookeeper.config;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
import java.util.List;
import java.util.UUID;
-
-import lombok.SneakyThrows;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryOneTime;
import org.apache.zookeeper.KeeperException;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.context.scope.refresh.RefreshScope;
+import org.springframework.cloud.endpoint.RefreshEndpoint;
import org.springframework.cloud.zookeeper.ZookeeperProperties;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
+import lombok.SneakyThrows;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
/**
* @author Spencer Gibb
*/
@@ -44,50 +53,78 @@ public class ZookeeperPropertySourceLocatorTests {
public static final String PREFIX = "test__config__";
public static final String ROOT = "/"+PREFIX + UUID.randomUUID();
private ConfigurableApplicationContext context;
+ public static final String KEY = ROOT + "/application/testProp";
+ @Configuration
+ @EnableAutoConfiguration
static class Config {
+ @Bean
+ public CountDownLatch countDownLatch() {
+ return new CountDownLatch(1);
+ }
+
+ @Bean
+ public RefreshEndpoint refreshEndpoint(ConfigurableApplicationContext context,
+ RefreshScope scope) {
+ RefreshEndpoint endpoint = new TestRefreshEndpoint(context, scope, countDownLatch());
+ return endpoint;
+ }
+ }
+
+ static class TestRefreshEndpoint extends RefreshEndpoint {
+ private CountDownLatch latch;
+
+ public TestRefreshEndpoint( ConfigurableApplicationContext context, RefreshScope scope, CountDownLatch latch) {
+ super(context, scope);
+ this.latch = latch;
+ }
+
+ @Override
+ public synchronized String[] refresh() {
+ String[] keys = super.refresh();
+ this.latch.countDown();
+ return keys;
+ }
}
CuratorFramework curator;
ZookeeperConfigProperties properties;
+ @Before
@SneakyThrows
- public void setup(boolean cacheEnabled) {
- curator = CuratorFrameworkFactory.builder()
+ public void setup() {
+ this.curator = CuratorFrameworkFactory.builder()
.retryPolicy(new RetryOneTime(500))
.connectString(new ZookeeperProperties().getConnectString())
.build();
- curator.start();
+ this.curator.start();
- List children = curator.getChildren().forPath("/");
+ List children = this.curator.getChildren().forPath("/");
for (String child : children) {
if (child.startsWith(PREFIX) && child.length() > PREFIX.length()) {
delete("/" + child);
}
}
- String key = ROOT + "/application/testProp";
- String create = curator.create().creatingParentsIfNeeded().forPath(key, "testPropVal".getBytes());
- curator.close();
+ String create = this.curator.create().creatingParentsIfNeeded().forPath(KEY, "testPropVal".getBytes());
+ this.curator.close();
System.out.println(create);
- context = new SpringApplicationBuilder(Config.class)
+ this.context = new SpringApplicationBuilder(Config.class)
.web(false)
.run("--spring.spring.application.name=testZkPropertySource",
- "--spring.cloud.zookeeper.config.cacheEnabled="+ cacheEnabled,
"--spring.cloud.zookeeper.config.root="+ROOT);
- curator = context.getBean(CuratorFramework.class);
- properties = context.getBean(ZookeeperConfigProperties.class);
- environment = context.getEnvironment();
-
+ this.curator = context.getBean(CuratorFramework.class);
+ this.properties = context.getBean(ZookeeperConfigProperties.class);
+ this.environment = context.getEnvironment();
}
@SneakyThrows
public void delete(String path) {
try {
- curator.delete().deletingChildrenIfNeeded().forPath(path);
+ this.curator.delete().deletingChildrenIfNeeded().forPath(path);
} catch (KeeperException e) {
if (e.code() != KeeperException.Code.NONODE) {
throw e;
@@ -95,6 +132,7 @@ public class ZookeeperPropertySourceLocatorTests {
}
}
+ @After
@SneakyThrows
public void after() {
try {
@@ -105,18 +143,17 @@ public class ZookeeperPropertySourceLocatorTests {
}
@Test
- public void propertyLoadedCached() {
- setup(true);
+ public void propertyLoadedAndUpdated() throws Exception {
String testProp = this.environment.getProperty("testProp");
assertThat("testProp was wrong", testProp, is(equalTo("testPropVal")));
- after();
- }
- @Test
- public void propertyLoadedNoCache() {
- setup(false);
- String testProp = this.environment.getProperty("testProp");
- assertThat("testProp was wrong", testProp, is(equalTo("testPropVal")));
- after();
+ this.curator.setData().forPath(KEY, "testPropValUpdate".getBytes());
+
+ CountDownLatch latch = this.context.getBean(CountDownLatch.class);
+ boolean receivedEvent = latch.await(5, TimeUnit.SECONDS);
+ assertThat("listener didn't receive event", receivedEvent, is(true));
+
+ testProp = this.environment.getProperty("testProp");
+ assertThat("testProp was wrong after update", testProp, is(equalTo("testPropValUpdate")));
}
}