commit 87357d27325c3d419e5e4533a22d0d057095e0c1 Author: Spencer Gibb Date: Wed Jan 28 14:35:15 2015 -0700 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8c5133e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*~ +#* +*# +.#* +.classpath +.project +.settings/ +.springBeans +target/ +_site/ +.idea +*.iml +*.swp diff --git a/README.md b/README.md new file mode 100644 index 00000000..9bd70f84 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +spring-cloud-zookeeper +=================== + +Developer Preview + +### TODO + +- [X] zookeeper config +- [X] zookeeper service discovery +- [X] zookeeper ribbon load balancer +- [ ] zookeeper ui +- [X] zookeeper property source +- [ ] zookeeper event bus + - [ ] send messages + - [ ] receive messages diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..387c3357 --- /dev/null +++ b/pom.xml @@ -0,0 +1,177 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + pom + Spring Cloud Zookeeper + Spring Cloud Zookeeper + + + org.springframework.cloud + spring-cloud-build + 1.0.0.BUILD-SNAPSHOT + + + + + + https://github.com/spring-cloud/spring-cloud-zookeeper + + scm:git:git://github.com/spring-cloud/spring-cloud-zookeeper.git + + + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-zookeeper.git + + HEAD + + + + spring-cloud-zookeeper-core + spring-cloud-zookeeper-config + spring-cloud-zookeeper-discovery + spring-cloud-zookeeper-bus + spring-cloud-zookeeper-sample + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + + + + + + org.springframework.cloud + spring-cloud-zookeeper-core + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-zookeeper-bus + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-zookeeper-config + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-zookeeper-discovery + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-commons + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-bus + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-amqp + + + org.springframework.integration + spring-integration-amqp + + + org.springframework.cloud + spring-cloud-spring-service-connector + + + + org.springframework.cloud + spring-cloud-localconfig-connector + + + + org.springframework.cloud + spring-cloud-cloudfoundry-connector + + + + + + org.springframework.cloud + spring-cloud-config-client + 1.0.0.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-netflix-core + 1.0.0.BUILD-SNAPSHOT + + + org.apache.curator + curator-framework + ${curator.version} + + + org.apache.curator + curator-recipes + ${curator.version} + + + org.apache.curator + curator-x-discovery + ${curator.version} + + + org.apache.curator + curator-test + ${curator.version} + test + + + com.netflix.ribbon + ribbon + ${ribbon.version} + + + com.netflix.ribbon + ribbon-core + ${ribbon.version} + + + com.netflix.ribbon + ribbon-httpclient + ${ribbon.version} + + + org.projectlombok + lombok + 1.12.6 + provided + + + com.google.guava + guava + 18.0 + + + + + + 2.7.0 + 2.0-RC9 + + + diff --git a/spring-cloud-zookeeper-bus/pom.xml b/spring-cloud-zookeeper-bus/pom.xml new file mode 100644 index 00000000..5d9c344b --- /dev/null +++ b/spring-cloud-zookeeper-bus/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + spring-cloud-zookeeper-bus + jar + Spring Cloud Zookeeper Bus + Spring Cloud Zookeeper Bus + + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + .. + + + + + org.springframework.cloud + spring-cloud-zookeeper-core + + + org.springframework.cloud + spring-cloud-bus + + + org.projectlombok + lombok + + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + + + + + diff --git a/spring-cloud-zookeeper-bus/src/main/java/org/springframework/cloud/zookeeper/bus/SimpleRemoteEvent.java b/spring-cloud-zookeeper-bus/src/main/java/org/springframework/cloud/zookeeper/bus/SimpleRemoteEvent.java new file mode 100644 index 00000000..3d567176 --- /dev/null +++ b/spring-cloud-zookeeper-bus/src/main/java/org/springframework/cloud/zookeeper/bus/SimpleRemoteEvent.java @@ -0,0 +1,27 @@ +package org.springframework.cloud.zookeeper.bus; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import lombok.Data; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; + +/** + * @author Spencer Gibb + */ +@JsonTypeName("simple") +@Data +public class SimpleRemoteEvent extends RemoteApplicationEvent { + + private String message; + + private SimpleRemoteEvent(){} + + public SimpleRemoteEvent(Object source, String originService, String destinationService, String message) { + super(source, originService, destinationService); + this.message = message; + } + + public SimpleRemoteEvent(Object source, String originService, String message) { + super(source, originService); + this.message = message; + } +} diff --git a/spring-cloud-zookeeper-bus/src/main/resources/META-INF/spring.factories b/spring-cloud-zookeeper-bus/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..9e6b2a84 --- /dev/null +++ b/spring-cloud-zookeeper-bus/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configuration +#org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +#org.springframework.cloud.zookeeper.bus.ZookeeperBusAutoConfiguration diff --git a/spring-cloud-zookeeper-config/pom.xml b/spring-cloud-zookeeper-config/pom.xml new file mode 100644 index 00000000..6f38498b --- /dev/null +++ b/spring-cloud-zookeeper-config/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + spring-cloud-zookeeper-config + jar + Spring Cloud Zookeeper Config + Spring Cloud Zookeeper Config + + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + .. + + + + + org.springframework.cloud + spring-cloud-zookeeper-core + + + org.springframework.cloud + spring-cloud-config-client + + + org.apache.curator + curator-recipes + + + org.projectlombok + lombok + + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + + + + + diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigBootstrapConfiguration.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigBootstrapConfiguration.java new file mode 100644 index 00000000..87408dee --- /dev/null +++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigBootstrapConfiguration.java @@ -0,0 +1,25 @@ +package org.springframework.cloud.zookeeper.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * @author Spencer Gibb + */ +@Configuration +@Import(ZookeeperAutoConfiguration.class) +@EnableConfigurationProperties +public class ZookeeperConfigBootstrapConfiguration { + @Bean + public ZookeeperPropertySourceLocator zookeeperPropertySourceLocator() { + return new ZookeeperPropertySourceLocator(); + } + + @Bean + public ZookeeperConfigProperties zookeeperConfigProperties() { + return new ZookeeperConfigProperties(); + } +} 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 new file mode 100644 index 00000000..8995032a --- /dev/null +++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperConfigProperties.java @@ -0,0 +1,16 @@ +package org.springframework.cloud.zookeeper.config; + +import lombok.Data; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Spencer Gibb + */ +@ConfigurationProperties("zookeeper.config") +@Data +public class ZookeeperConfigProperties { + private boolean enabled = true; + + private String root = "config"; +} diff --git a/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySource.java b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySource.java new file mode 100644 index 00000000..1341fce0 --- /dev/null +++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySource.java @@ -0,0 +1,98 @@ +package org.springframework.cloud.zookeeper.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.Lifecycle; +import org.springframework.core.env.EnumerablePropertySource; + +import com.google.common.base.Charsets; + +/** + * @author Spencer Gibb + */ +public class ZookeeperPropertySource extends EnumerablePropertySource + implements Lifecycle { + private static final Logger LOG = LoggerFactory + .getLogger(ZookeeperPropertySource.class); + + private String context; + + private TreeCache cache; + private boolean running; + + public ZookeeperPropertySource(String context, CuratorFramework source) { + super(context, source); + this.context = context; + + if (!this.context.startsWith("/")) { + this.context = "/" + this.context; + } + } + + @Override + public void start() { + try { + cache = TreeCache.newBuilder(source, context).build(); + cache.start(); + running = true; + } + catch (NoNodeException e) { + // no node, ignore + } + catch (Exception e) { + LOG.error("Error initializing ZookeperPropertySource", e); + } + } + + @Override + public Object getProperty(String name) { + String fullPath = context + "/" + name.replace(".", "/"); + ChildData data = cache.getCurrentData(fullPath); + if (data == null) + return null; + return new String(data.getData(), Charsets.UTF_8); + } + + @Override + public String[] getPropertyNames() { + List keys = new ArrayList<>(); + findKeys(keys, context); + return keys.toArray(new String[0]); + } + + protected void findKeys(List keys, String path) { + Map children = cache.getCurrentChildren(path); + + if (children == null) + return; + for (Map.Entry entry : children.entrySet()) { + ChildData child = entry.getValue(); + if (child.getData().length == 0) { + findKeys(keys, child.getPath()); + } + else { + keys.add(child.getPath().replace(context + "/", "").replace('/', '.')); + } + } + } + + @Override + public void stop() { + cache.close(); + running = false; + } + + @Override + public boolean isRunning() { + return running; + } + +} 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 new file mode 100644 index 00000000..948d6656 --- /dev/null +++ b/spring-cloud-zookeeper-config/src/main/java/org/springframework/cloud/zookeeper/config/ZookeeperPropertySourceLocator.java @@ -0,0 +1,75 @@ +package org.springframework.cloud.zookeeper.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.PreDestroy; + +import org.apache.curator.framework.CuratorFramework; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.config.client.PropertySourceLocator; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; + +/** + * @author Spencer Gibb + */ +public class ZookeeperPropertySourceLocator implements PropertySourceLocator { + + @Autowired + private ZookeeperConfigProperties properties; + + @Autowired + private CuratorFramework curator; + + @Override + public PropertySource locate(Environment environment) { + if (environment instanceof ConfigurableEnvironment) { + ConfigurableEnvironment env = (ConfigurableEnvironment) environment; + String appName = env.getProperty("spring.application.name"); + List profiles = Arrays.asList(env.getActiveProfiles()); + + String root = properties.getRoot(); + List contexts = new ArrayList<>(); + + String defaultContext = root + "/application"; + contexts.add(defaultContext); + addProfiles(contexts, defaultContext, profiles); + + String baseContext = root + "/" + appName; + contexts.add(baseContext); + addProfiles(contexts, baseContext, profiles); + + CompositePropertySource composite = new CompositePropertySource("zookeeper"); + + for (String propertySourceContext : contexts) { + ZookeeperPropertySource propertySource = create(propertySourceContext); + propertySource.start(); + composite.addPropertySource(propertySource); + // TODO: howto call close when /refresh + } + + return composite; + } + return null; + } + + @PreDestroy + public void destroy() { + // TODO: call close on zkps's + } + + private ZookeeperPropertySource create(String context) { + return new ZookeeperPropertySource(context, curator); + } + + private void addProfiles(List contexts, String baseContext, + List profiles) { + for (String profile : profiles) { + contexts.add(baseContext + "::" + profile); + } + } +} 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 new file mode 100644 index 00000000..d1701df5 --- /dev/null +++ b/spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap Configuration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.zookeeper.config.ZookeeperConfigBootstrapConfiguration diff --git a/spring-cloud-zookeeper-core/pom.xml b/spring-cloud-zookeeper-core/pom.xml new file mode 100644 index 00000000..cd595062 --- /dev/null +++ b/spring-cloud-zookeeper-core/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + spring-cloud-zookeeper-core + jar + Spring Cloud Zookeeper Core + Spring Cloud Zookeeper Core + + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + .. + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-commons + + + org.projectlombok + lombok + + provided + + + org.apache.curator + curator-framework + + + org.apache.curator + curator-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + + + + + diff --git a/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfiguration.java b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfiguration.java new file mode 100644 index 00000000..c2d8596e --- /dev/null +++ b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfiguration.java @@ -0,0 +1,56 @@ +package org.springframework.cloud.zookeeper; + +import javax.annotation.PreDestroy; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Spencer Gibb + */ +@Configuration +@EnableConfigurationProperties +public class ZookeeperAutoConfiguration { + @Bean + @ConditionalOnMissingBean + public ZookeeperProperties zookeeperProperties() { + return new ZookeeperProperties(); + } + + @Bean + @ConditionalOnMissingBean + public CuratorFramework curatorFramework() { + CuratorFramework curator = CuratorFrameworkFactory.builder() + // TODO: configurable retry policy + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + // .retryPolicy(new RetryOneTime(100)) + // TODO: support ensembleProvider via ExhibitorEnsembleProvider + // .ensembleProvider(new ExhibitorEnsembleProvider()) + .connectString(zookeeperProperties().getConnectString()).build(); + curator.start(); + return curator; + } + + @PreDestroy + public void shutdown() { + curatorFramework().close(); + } + + @Bean + @ConditionalOnMissingBean + public ZookeeperEndpoint zookeeperEndpoint() { + return new ZookeeperEndpoint(); + } + + @Bean + @ConditionalOnMissingBean + public ZookeeperHealthIndicator zookeeperHealthIndicator() { + return new ZookeeperHealthIndicator(); + } + +} diff --git a/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperEndpoint.java b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperEndpoint.java new file mode 100644 index 00000000..0911aaea --- /dev/null +++ b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperEndpoint.java @@ -0,0 +1,29 @@ +package org.springframework.cloud.zookeeper; + +import lombok.Data; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.AbstractEndpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Spencer Gibb + */ +@ConfigurationProperties(prefix = "endpoints.zookeeper", ignoreUnknownFields = false) +public class ZookeeperEndpoint extends AbstractEndpoint { + + @Autowired + public ZookeeperEndpoint() { + super("zookeeper", false, true); + } + + @Override + public ZookeeperData invoke() { + ZookeeperData data = new ZookeeperData(); + return data; + } + + @Data + public static class ZookeeperData { + } +} diff --git a/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperHealthIndicator.java b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperHealthIndicator.java new file mode 100644 index 00000000..0edb067a --- /dev/null +++ b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperHealthIndicator.java @@ -0,0 +1,36 @@ +package org.springframework.cloud.zookeeper; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.imps.CuratorFrameworkState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; + +/** + * @author Spencer Gibb + */ +public class ZookeeperHealthIndicator extends AbstractHealthIndicator { + @Autowired + CuratorFramework curator; + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + try { + if (curator.getState() != CuratorFrameworkState.STARTED) { + builder.down().withDetail("error", "Client not started"); + } + else if (curator.checkExists().forPath("/") == null) { + builder.down().withDetail("error", "Root for namespace does not exist"); + } + else { + builder.up(); + } + builder.withDetail("connectionString", + curator.getZookeeperClient().getCurrentConnectionString()) + .withDetail("state", curator.getState()); + } + catch (Exception e) { + builder.down(e); + } + } +} diff --git a/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperProperties.java b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperProperties.java new file mode 100644 index 00000000..3010dfbe --- /dev/null +++ b/spring-cloud-zookeeper-core/src/main/java/org/springframework/cloud/zookeeper/ZookeeperProperties.java @@ -0,0 +1,19 @@ +package org.springframework.cloud.zookeeper; + +import javax.validation.constraints.NotNull; + +import lombok.Data; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Spencer Gibb + */ +@ConfigurationProperties("zookeeper") +@Data +public class ZookeeperProperties { + @NotNull + private String connectString = "localhost:2181"; + + private boolean enabled = true; +} diff --git a/spring-cloud-zookeeper-core/src/main/resources/META-INF/spring.factories b/spring-cloud-zookeeper-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..ae022cd4 --- /dev/null +++ b/spring-cloud-zookeeper-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configuration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration diff --git a/spring-cloud-zookeeper-core/src/test/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfigurationTests.java b/spring-cloud-zookeeper-core/src/test/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfigurationTests.java new file mode 100644 index 00000000..a7f754cf --- /dev/null +++ b/spring-cloud-zookeeper-core/src/test/java/org/springframework/cloud/zookeeper/ZookeeperAutoConfigurationTests.java @@ -0,0 +1,43 @@ +package org.springframework.cloud.zookeeper; + +import static org.junit.Assert.assertNotNull; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.test.TestingServer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Spencer Gibb + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { ZookeeperAutoConfigurationTests.TestConfig.class, + ZookeeperAutoConfiguration.class }) +public class ZookeeperAutoConfigurationTests { + + @Autowired(required = false) + CuratorFramework curator; + + @Test + public void testZookeeperFramework() { + assertNotNull("curator is null", curator); + } + + static class TestConfig { + @Bean + public ZookeeperProperties zookeeperProperties() throws Exception { + ZookeeperProperties properties = new ZookeeperProperties(); + properties.setConnectString(testingServer().getConnectString()); + return properties; + } + + @Bean + public TestingServer testingServer() throws Exception { + return new TestingServer(); + } + } +} diff --git a/spring-cloud-zookeeper-discovery/pom.xml b/spring-cloud-zookeeper-discovery/pom.xml new file mode 100644 index 00000000..e499f767 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + spring-cloud-zookeeper-discovery + jar + Spring Cloud Zookeeper Discovery + Spring Cloud Zookeeper Discovery + + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + .. + + + + + org.springframework.cloud + spring-cloud-zookeeper-core + + + org.apache.curator + curator-x-discovery + + + org.springframework.cloud + spring-cloud-netflix-core + + + com.netflix.ribbon + ribbon + + + com.netflix.ribbon + ribbon-core + + + com.netflix.ribbon + ribbon-httpclient + + + org.projectlombok + lombok + + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.guava + guava + + + + diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/RibbonZookeeperAutoConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/RibbonZookeeperAutoConfiguration.java new file mode 100644 index 00000000..f45f1c19 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/RibbonZookeeperAutoConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2014 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.discovery; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonClients; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Configuration; + +/** + * @author Dave Syer + */ +@Configuration +@EnableConfigurationProperties +@ConditionalOnBean(SpringClientFactory.class) +@ConditionalOnProperty(value = "ribbon.zookeeper.enabled", matchIfMissing = true) +@AutoConfigureAfter(RibbonAutoConfiguration.class) +@RibbonClients(defaultConfiguration = ZookeeperRibbonClientConfiguration.class) +public class RibbonZookeeperAutoConfiguration { + + +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java new file mode 100644 index 00000000..7a692a49 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClient.java @@ -0,0 +1,111 @@ +package org.springframework.cloud.zookeeper.discovery; + +import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; + +import lombok.SneakyThrows; + +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.ApplicationContext; + +import com.google.common.base.Function; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; + +/** + * @author Spencer Gibb + */ +public class ZookeeperDiscoveryClient implements DiscoveryClient { + + @Autowired + ApplicationContext context; + + @Autowired(required = false) + ServiceInstance instance; + + @Autowired + ServiceDiscovery discovery; + + @Override + public String description() { + return "Spring Cloud Zookeeper Discovery Client"; + } + + @Override + public org.springframework.cloud.client.ServiceInstance getLocalServiceInstance() { + if (instance == null) { + throw new IllegalStateException("Unable to locate instance in zookeeper: " + + context.getId()); + } + return new DefaultServiceInstance(instance.getId(), instance.getAddress(), + instance.getPort()); + } + + @Override + @SneakyThrows + public List getInstances( + final String serviceId) { + Collection> zkInstances = discovery + .queryForInstances(serviceId); + + Iterable instances = transform( + zkInstances, + new Function, org.springframework.cloud.client.ServiceInstance>() { + @Nullable + @Override + public org.springframework.cloud.client.ServiceInstance apply( + @Nullable ServiceInstance input) { + return new DefaultServiceInstance(serviceId, input.getAddress(), + input.getPort()); + } + }); + + return Lists.newArrayList(instances); + } + + @Override + @SneakyThrows + public List getAllInstances() { + Iterable instances = transform( + concat(transform( + discovery.queryForNames(), + new Function>>() { + @SneakyThrows + public Collection> apply( + String input) { + return discovery.queryForInstances(input); + } + })), + new Function, org.springframework.cloud.client.ServiceInstance>() { + public org.springframework.cloud.client.ServiceInstance apply( + ServiceInstance input) { + return new DefaultServiceInstance(input.getName(), input + .getAddress(), input.getPort()); + } + }); + + return Lists.newArrayList(instances); + } + + @Override + public List getServices() { + ArrayList services = null; + try { + services = Lists.newArrayList(discovery.queryForNames()); + } + catch (Exception e) { + Throwables.propagate(e); + } + return services; + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java new file mode 100644 index 00000000..08e35d15 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryClientConfiguration.java @@ -0,0 +1,70 @@ +package org.springframework.cloud.zookeeper.discovery; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; +import org.apache.curator.x.discovery.ServiceInstance; +import org.apache.curator.x.discovery.UriSpec; +import org.apache.curator.x.discovery.details.InstanceSerializer; +import org.apache.curator.x.discovery.details.JsonInstanceSerializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; + +/** + * @author Spencer Gibb + */ +@Configuration +@EnableConfigurationProperties +public class ZookeeperDiscoveryClientConfiguration { + @Autowired + ApplicationContext context; + + @Bean + public ZookeeperDiscoveryProperties zookeeperDiscoveryProperties() { + return new ZookeeperDiscoveryProperties(); + } + + @Bean + public ZookeeperLifecycle zookeeperLifecycle() { + return new ZookeeperLifecycle(); + } + + @Bean + public ZookeeperDiscoveryClient zookeeperDiscoveryClient() { + return new ZookeeperDiscoveryClient(); + } + + @Bean + public ServiceInstance serviceInstance() throws Exception { + Environment environment = context.getEnvironment(); + Integer port = new Integer(environment.getProperty("server.port", "8080")); + UriSpec uriSpec = new UriSpec(zookeeperDiscoveryProperties().getUriSpec()); + return ServiceInstance. builder() + .name(environment.getProperty("spring.application.name")) + .payload(new ZookeeperInstance(context.getId())).port(port) + .uriSpec(uriSpec).build(); + } + + @Bean + public InstanceSerializer instanceSerializer() { + return new JsonInstanceSerializer<>(ZookeeperInstance.class); + } + + @Bean + public ServiceDiscovery serviceDiscovery(CuratorFramework curator) + throws Exception { + return ServiceDiscoveryBuilder.builder(ZookeeperInstance.class).client(curator) + .basePath(zookeeperDiscoveryProperties().getRoot()) + .serializer(instanceSerializer()).thisInstance(serviceInstance()).build(); + } + + @Bean + public ZookeeperDiscoveryHealthIndicator zookeeperDiscoveryHealthIndicator() { + return new ZookeeperDiscoveryHealthIndicator(); + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java new file mode 100644 index 00000000..3bc02833 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryHealthIndicator.java @@ -0,0 +1,41 @@ +package org.springframework.cloud.zookeeper.discovery; + +import java.util.ArrayList; +import java.util.Collection; + +import lombok.extern.slf4j.Slf4j; + +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; + +/** + * @author Spencer Gibb + */ +@Slf4j +public class ZookeeperDiscoveryHealthIndicator extends AbstractHealthIndicator { + @Autowired + ServiceDiscovery serviceDiscovery; + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + try { + Collection names = serviceDiscovery.queryForNames(); + ArrayList> allInstances = new ArrayList<>(); + for (String name : names) { + Collection> instances = serviceDiscovery + .queryForInstances(name); + for (ServiceInstance instance : instances) { + allInstances.add(instance); + } + } + builder.up().withDetail("services", allInstances); + } + catch (Exception e) { + log.error("Error", e); + builder.down(e); + } + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryProperties.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryProperties.java new file mode 100644 index 00000000..f79c2216 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperDiscoveryProperties.java @@ -0,0 +1,18 @@ +package org.springframework.cloud.zookeeper.discovery; + +import lombok.Data; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Spencer Gibb + */ +@ConfigurationProperties("zookeeper.discovery") +@Data +public class ZookeeperDiscoveryProperties { + private boolean enabled = true; + + private String root = "/services"; + + private String uriSpec = "{scheme}://{address}:{port}"; +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperInstance.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperInstance.java new file mode 100644 index 00000000..5585f863 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperInstance.java @@ -0,0 +1,16 @@ +package org.springframework.cloud.zookeeper.discovery; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author Spencer Gibb + */ +@Data +@AllArgsConstructor +public class ZookeeperInstance { + private String id; + + private ZookeeperInstance() { + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java new file mode 100644 index 00000000..db4cbab7 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperLifecycle.java @@ -0,0 +1,51 @@ +package org.springframework.cloud.zookeeper.discovery; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle; + +/** + * @author Spencer Gibb + */ +@Slf4j +public class ZookeeperLifecycle extends AbstractDiscoveryLifecycle { + + @Autowired + private ZookeeperDiscoveryProperties properties; + + @Autowired + private ServiceDiscovery serviceDiscovery; + + @Autowired + private ServiceInstance instance; + + @Override + @SneakyThrows + protected void register() { + serviceDiscovery.start(); + } + + // TODO: implement registerManagement + + @Override + @SneakyThrows + protected void deregister() { + serviceDiscovery.unregisterService(instance); + } + + // TODO: implement deregisterManagement + + @Override + protected boolean isEnabled() { + return properties.isEnabled(); + } + + @Override + protected Object getConfiguration() { + return properties; + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java new file mode 100644 index 00000000..df398df8 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperRibbonClientConfiguration.java @@ -0,0 +1,88 @@ +/* + * 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.discovery; + +import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses; +import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity; + +import javax.annotation.PostConstruct; + +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.client.config.IClientConfig; +import com.netflix.config.ConfigurationManager; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicStringProperty; +import com.netflix.loadbalancer.ServerList; + +/** + * Preprocessor that configures defaults for eureka-discovered ribbon clients. Such as: + * @zone, NIWSServerListClassName, DeploymentContextBasedVipAddresses, + * NFLoadBalancerRuleClassName, NIWSServerListFilterClassName and more + * + * @author Spencer Gibb + * @author Dave Syer + */ +@Configuration +public class ZookeeperRibbonClientConfiguration { + protected static final String VALUE_NOT_SET = "__not__set__"; + protected static final String DEFAULT_NAMESPACE = "ribbon"; + @Autowired + private ServiceDiscovery serviceDiscovery; + @Value("${ribbon.client.name}") + private String serviceId = "client"; + + public ZookeeperRibbonClientConfiguration() { + } + + @Bean + @ConditionalOnMissingBean + public ServerList ribbonServerList(IClientConfig config) { + ZookeeperServerList serverList = new ZookeeperServerList(serviceDiscovery); + serverList.initWithNiwsConfig(config); + return serverList; + } + + @PostConstruct + public void preprocess() { + setProp(this.serviceId, DeploymentContextBasedVipAddresses.key(), this.serviceId); + setProp(this.serviceId, EnableZoneAffinity.key(), "true"); + } + + protected void setProp(String serviceId, String suffix, String value) { + // how to set the namespace properly? + String key = getKey(serviceId, suffix); + DynamicStringProperty property = getProperty(key); + if (property.get().equals(VALUE_NOT_SET)) { + ConfigurationManager.getConfigInstance().setProperty(key, value); + } + } + + protected DynamicStringProperty getProperty(String key) { + return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET); + } + + protected String getKey(String serviceId, String suffix) { + return serviceId + "." + DEFAULT_NAMESPACE + "." + suffix; + } + +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServer.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServer.java new file mode 100644 index 00000000..e8c85b55 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServer.java @@ -0,0 +1,44 @@ +package org.springframework.cloud.zookeeper.discovery; + +import org.apache.curator.x.discovery.ServiceInstance; + +import com.netflix.loadbalancer.Server; + +/** + * @author Spencer Gibb + */ +public class ZookeeperServer extends Server { + + private final MetaInfo metaInfo; + + public ZookeeperServer(final ServiceInstance instance) { + // TODO: ssl support + super(instance.getAddress(), instance.getPort()); + metaInfo = new MetaInfo() { + @Override + public String getAppName() { + return instance.getName(); + } + + @Override + public String getServerGroup() { + return null; + } + + @Override + public String getServiceIdForDiscovery() { + return null; + } + + @Override + public String getInstanceId() { + return instance.getId(); + } + }; + } + + @Override + public MetaInfo getMetaInfo() { + return metaInfo; + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java new file mode 100644 index 00000000..4a7fbe39 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/java/org/springframework/cloud/zookeeper/discovery/ZookeeperServerList.java @@ -0,0 +1,73 @@ +package org.springframework.cloud.zookeeper.discovery; + +import static com.google.common.collect.Collections2.transform; +import static com.google.common.collect.Lists.newArrayList; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nullable; + +import org.apache.curator.x.discovery.ServiceDiscovery; +import org.apache.curator.x.discovery.ServiceInstance; + +import com.google.common.base.Function; +import com.google.common.base.Throwables; +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractServerList; + +/** + * @author Spencer Gibb + */ +public class ZookeeperServerList extends AbstractServerList { + + private String serviceId; + private final ServiceDiscovery serviceDiscovery; + + public ZookeeperServerList(ServiceDiscovery serviceDiscovery) { + this.serviceDiscovery = serviceDiscovery; + } + + @Override + public void initWithNiwsConfig(IClientConfig clientConfig) { + this.serviceId = clientConfig.getClientName(); + } + + @Override + public List getInitialListOfServers() { + return getServers(); + } + + @Override + public List getUpdatedListOfServers() { + return getServers(); + } + + @SuppressWarnings("unchecked") + private List getServers() { + try { + Collection> instances = serviceDiscovery + .queryForInstances(serviceId); + if (instances == null || instances.isEmpty()) { + return Collections.EMPTY_LIST; + } + Collection servers = transform(instances, + new Function, ZookeeperServer>() { + @Nullable + @Override + public ZookeeperServer apply( + @Nullable ServiceInstance instance) { + ZookeeperServer server = new ZookeeperServer(instance); + return server; + } + }); + + return newArrayList(servers); + } + catch (Exception e) { + Throwables.propagate(e); + } + return Collections.EMPTY_LIST; + } +} diff --git a/spring-cloud-zookeeper-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-zookeeper-discovery/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..fbae79c4 --- /dev/null +++ b/spring-cloud-zookeeper-discovery/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +# Auto Configuration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.zookeeper.discovery.RibbonZookeeperAutoConfiguration + +org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ +org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClientConfiguration diff --git a/spring-cloud-zookeeper-sample/pom.xml b/spring-cloud-zookeeper-sample/pom.xml new file mode 100644 index 00000000..6f1c6658 --- /dev/null +++ b/spring-cloud-zookeeper-sample/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + spring-cloud-zookeeper-sample + jar + Spring Cloud Zookeeper Sample + Spring Cloud Zookeeper Sample + + + org.springframework.cloud + spring-cloud-zookeeper + 1.0.0.BUILD-SNAPSHOT + .. + + + + + + + maven-deploy-plugin + + true + + + + + + + + org.springframework.boot + spring-boot-starter-web + test + + + org.springframework.cloud + spring-cloud-zookeeper-config + test + + + org.springframework.cloud + spring-cloud-zookeeper-discovery + test + + + org.springframework.cloud + spring-cloud-zookeeper-bus + test + + + org.projectlombok + lombok + test + + + + diff --git a/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java b/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java new file mode 100644 index 00000000..f71d2dde --- /dev/null +++ b/spring-cloud-zookeeper-sample/src/test/java/org/springframework/cloud/zookeeper/sample/SampleApplication.java @@ -0,0 +1,67 @@ +package org.springframework.cloud.zookeeper.sample; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.cloud.bus.jackson.SubtypeModule; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.zookeeper.bus.SimpleRemoteEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Spencer Gibb + */ +@Configuration +@EnableAutoConfiguration +@EnableDiscoveryClient +@RestController +@Slf4j +public class SampleApplication implements ApplicationListener { + + public static final String CLIENT_NAME = "testZookeeperApp"; + + @Autowired + LoadBalancerClient loadBalancer; + + @Autowired + Environment env; + + @Autowired(required = false) + RelaxedPropertyResolver resolver; + + public static void main(String[] args) { + SpringApplication.run(SampleApplication.class, args); + } + + @RequestMapping("/") + public ServiceInstance lb() { + return loadBalancer.choose(CLIENT_NAME); + } + + @RequestMapping("/myenv") + public String env(@RequestParam("prop") String prop) { + String property = new RelaxedPropertyResolver(env).getProperty(prop, "Not Found"); + return property; + } + + @Bean + public SubtypeModule sampleSubtypeModule() { + return new SubtypeModule(SimpleRemoteEvent.class); + } + + @Override + public void onApplicationEvent(SimpleRemoteEvent event) { + log.info("Received event: {}", event); + } +} diff --git a/spring-cloud-zookeeper-sample/src/test/resources/application.yml b/spring-cloud-zookeeper-sample/src/test/resources/application.yml new file mode 100644 index 00000000..f37d8455 --- /dev/null +++ b/spring-cloud-zookeeper-sample/src/test/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 8080 + +#TODO: figure out why I need this here and in bootstrap.yml +spring: + application: + name: testZookeeperApp + +endpoints: + restart: + enabled: true + shutdown: + enabled: true + health: + sensitive: false \ No newline at end of file diff --git a/spring-cloud-zookeeper-sample/src/test/resources/bootstrap.yml b/spring-cloud-zookeeper-sample/src/test/resources/bootstrap.yml new file mode 100644 index 00000000..6605f314 --- /dev/null +++ b/spring-cloud-zookeeper-sample/src/test/resources/bootstrap.yml @@ -0,0 +1,7 @@ +spring: + application: + name: testZookeeperApp + cloud: + config: + # TODO: refactor spring-cloud-config to use refresh, etc.. with out config client + enabled: false