Permalink
Browse files

Move Archaius bindings to this repository.

  • Loading branch information...
1 parent 5626904 commit 940358ff1a6a60f82c25679fffcf734bf67be423 @Kami Kami committed Mar 26, 2013
View
@@ -19,6 +19,7 @@
<module>service-registry-client</module>
<module>service-registry-examples</module>
<module>service-registry-curator</module>
+ <module>service-registry-archaius</module>
</modules>
<developers>
@@ -0,0 +1,25 @@
+# Service Registry Provider for Archaius
+
+This library provides bindings for the [Archaius Library](https://github.com/Netflix/archaius). That library provides a set of configuration management API's for
+managing values.
+
+This particular extension provides a new `source` called the `ServiceRegistryConfigurationProvider`. It
+provides a configuration source backed by [Rackspace Service Registry](http://www.rackspace.com/blog/keep-track-of-your-services-and-applications-with-the-new-rackspace-service-registry/).
+It works in an idiomatic archaius way which plugs in with the rest of the system.
+
+Here is a snippet of example code
+
+```java
+final Client client = new Client(System.getProperty("rackspace.serviceregistry.username"),
+ System.getProperty("rackspace.serviceregistry.apikey"),
+ Region.US);
+PolledConfigurationSource configSource = new ServiceRegistryConfigurationProvider(client);
+AbstractPollingScheduler scheduler = new FixedDelayPollingScheduler();
+DynamicConfiguration config = new DynamicConfiguration(configSource, scheduler);
+```
+
+# TODO
+
+* Upload a maven artifact
+* Add more tests
+* Add docs around the service bindings
@@ -0,0 +1,79 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.rackspacecloud</groupId>
+ <artifactId>service-registry-parent</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <name>Service Registry Client Archaius Bindings</name>
+ <artifactId>service-registry-archaius</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <repositories>
+ <repository>
+ <id>sonatype-nexus-snapshots</id>
+ <name>Nexus Snapshots Repository</name>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.netflix.archaius</groupId>
+ <artifactId>archaius-core</artifactId>
+ <version>0.5.3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.rackspacecloud</groupId>
+ <artifactId>service-registry-client</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.0.9</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
@@ -0,0 +1,12 @@
+package com.netflix.config.sources;
+
+import com.rackspacecloud.client.service_registry.objects.ConfigurationValue;
+import com.rackspacecloud.client.service_registry.objects.Service;
+
+import java.util.List;
+
+public interface ServiceRegistryClient {
+ List<Service> getServices(String tag) throws Exception;
+
+ List<ConfigurationValue> getConfiguration() throws Exception;
+}
@@ -0,0 +1,24 @@
+package com.netflix.config.sources;
+
+import com.rackspacecloud.client.service_registry.Client;
+import com.rackspacecloud.client.service_registry.objects.ConfigurationValue;
+import com.rackspacecloud.client.service_registry.objects.Service;
+
+import java.util.List;
+
+public class ServiceRegistryClientProvider implements ServiceRegistryClient {
+ private final Client client;
+
+ public ServiceRegistryClientProvider(String user, String key, String region) {
+ client = new Client(user, key, region);
+ }
+ @Override
+ public List<Service> getServices(String tag) throws Exception {
+ return client.services.list(null, tag);
+ }
+
+ @Override
+ public List<ConfigurationValue> getConfiguration() throws Exception {
+ return client.configuration.list(null);
+ }
+}
@@ -0,0 +1,87 @@
+package com.netflix.config.sources;
+
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+import com.netflix.config.PollResult;
+import com.netflix.config.PolledConfigurationSource;
+import com.rackspacecloud.client.service_registry.objects.ConfigurationValue;
+import com.rackspacecloud.client.service_registry.objects.Service;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.util.*;
+
+public class ServiceRegistryConfigurationProvider implements PolledConfigurationSource {
+
+ private static Logger logger = LoggerFactory.getLogger(ServiceRegistryConfigurationProvider.class);
+
+ private static final String DELIMITER =".";
+ public static final String PREFIX = "serverset";
+ public static final String INTEREST = PREFIX + DELIMITER + "interest";
+ private static final String SEPARATOR = ",";
+ private static final String SUFFIX = "addresses";
+
+ public static final DynamicStringProperty dynamicServiceTags = DynamicPropertyFactory.getInstance().getStringProperty(INTEREST, "");
+
+ private final ServiceRegistryClient client;
+
+ public ServiceRegistryConfigurationProvider(ServiceRegistryClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public PollResult poll(boolean initial, Object checkPoint)
+ throws Exception {
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ for (ConfigurationValue value : client.getConfiguration()) {
+ map.put(value.getId(), value.getValue());
+ }
+
+ // Do a query to get all the service tags we're interested in,
+ // once we have that we'll namespace the parameters
+ String tags = dynamicServiceTags.get();
+ if (!tags.isEmpty()) {
+ Set<String> serviceTags = new HashSet<String>(Arrays.asList(tags.split(SEPARATOR)));
+ for (String tag: serviceTags) {
+ Set<InetSocketAddress> pairs = new HashSet<InetSocketAddress>();
+ String key = PREFIX + DELIMITER + tag + DELIMITER + SUFFIX;
+ for (Service service : client.getServices(tag)) {
+ pairs.add(getHostPortPair(service));
+ }
+ if (!pairs.isEmpty()) {
+ map.put(key, StringUtils.join(pairs, SEPARATOR));
+ }
+ }
+ }
+ return PollResult.createFull(map);
+ }
+
+ @Override
+ public String toString() {
+ return "ServiceRegistryConfigurationProvider [client=" + client.toString() + "]";
+ }
+
+ /**
+ * Safely get the information from our convention
+ * @param svc
+ * @return
+ */
+ public static InetSocketAddress getHostPortPair(Service svc) {
+ try {
+ return new InetSocketAddress(svc.getMetadata().get("service.host"),
+ Integer.parseInt(svc.getMetadata().get("service.port")));
+ } catch (Exception e) {
+ logger.error("Exception extracting metadata from service instance {}", svc, e);
+ return null;
+ }
+ }
+
+ public static Service setHostPortPair(String host, int port, Service svc) {
+ svc.getMetadata().put("service.host", host);
+ svc.getMetadata().put("service.port", String.valueOf(port));
+ return svc;
+ }
+}
@@ -0,0 +1,134 @@
+package com.netflix.config.sources.test;
+
+
+import com.netflix.config.*;
+import com.netflix.config.sources.ServiceRegistryConfigurationProvider;
+import com.rackspacecloud.client.service_registry.objects.Service;
+import org.apache.commons.configuration.AbstractConfiguration;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+public class ServiceRegistryConfigurationProviderTest {
+
+ private static TestServiceRegistryConfigurationProvider testInstance;
+ private static PolledConfigurationSource src;
+ private static final Logger logger = LoggerFactory.getLogger(ServiceRegistryConfigurationProviderTest.class);
+ private static AbstractPollingScheduler simplePollingScheduler;
+ private static DynamicConfiguration dynamicConfiguration;
+
+ public String getRandomTag() {
+ byte diff = 'z' - 'a';
+ byte[] bytes = new byte[5];
+ StringBuilder sb = new StringBuilder();
+ new Random().nextBytes(bytes);
+ for (byte b : bytes) {
+ sb.append((char)('a' + Math.abs(b % diff)));
+ }
+ logger.info("Random tag generated '{}'", sb.toString());
+ return sb.toString();
+ }
+ public void pollOnce() {
+ dynamicConfiguration.startPolling(src, simplePollingScheduler);
+ }
+
+ @BeforeClass
+ public static void beforeClass() {
+ testInstance = new TestServiceRegistryConfigurationProvider();
+ src = new ServiceRegistryConfigurationProvider(testInstance);
+ simplePollingScheduler = new AbstractPollingScheduler() {
+ @Override
+ protected void schedule(Runnable pollingRunnable) {
+ logger.info("Scheduling poller");
+ pollingRunnable.run();
+ }
+
+ @Override
+ public void stop() {
+ logger.info("Stopping logger");
+ }
+ };
+
+ // Inject initial properties
+ HashMap<String, Object> cfg = new HashMap<String, Object>();
+
+ AbstractConfiguration configuration = new ConcurrentMapConfiguration(cfg);
+ dynamicConfiguration = new DynamicConfiguration(src, simplePollingScheduler);
+
+ ConcurrentCompositeConfiguration finalConfig = new ConcurrentCompositeConfiguration();
+
+ // add them in this order to make dynamicConfig override configuration
+ finalConfig.addConfiguration(dynamicConfiguration);
+ finalConfig.addConfiguration(configuration);
+
+ ConfigurationManager.install(finalConfig);
+
+ }
+
+ @Test
+ public void testPolling() throws Exception {
+ String host = "host";
+ int port = 92;
+ String tag = getRandomTag();
+
+ ConfigurationManager.getConfigInstance().setProperty(ServiceRegistryConfigurationProvider.INTEREST, tag);
+
+ for (int i = 0; i < 10; i++) {
+ testInstance.addService(tag, ServiceRegistryConfigurationProvider.setHostPortPair(
+ host,
+ port,
+ new Service("faux" + i, "fauxSession", Collections.singletonList(tag), new HashMap<String, String>())));
+ }
+ String key = ServiceRegistryConfigurationProvider.PREFIX + "." + tag + ".addresses";
+ pollOnce();
+
+ Assert.assertEquals(new InetSocketAddress(host, port).toString(),
+ ConfigurationManager.getConfigInstance().getString(key));
+ }
+
+ @Test
+ public void testPollingChanging() throws Exception {
+ String host = "localhost";
+ int port = 92;
+ String[] tags = {getRandomTag(), getRandomTag()};
+ ConfigurationManager.getConfigInstance().setProperty(
+ ServiceRegistryConfigurationProvider.INTEREST, StringUtils.join(tags, ","));
+ Map<String, Integer> scoreboard = new HashMap<String, Integer>();
+
+ for (int i = 0; i < tags.length; i++) {
+ for (int j = 0; j < 5; j++) {
+ String realHost = host + i + j;
+ testInstance.addService(tags[i], ServiceRegistryConfigurationProvider.setHostPortPair(
+ host + i + j,
+ port,
+ new Service("faux" + i + j, "fauxSession", Collections.singletonList(tags[i]), new HashMap<String, String>())));
+
+
+ Integer score = scoreboard.get(tags[i]);
+ if (score == null) {
+ scoreboard.put(tags[i], 1);
+ } else {
+ scoreboard.put(tags[i], score + 1);
+ }
+ }
+ }
+
+ String firstKey = ServiceRegistryConfigurationProvider.PREFIX + "." + tags[0] + ".addresses";
+ String secondKey = ServiceRegistryConfigurationProvider.PREFIX + "." + tags[1] + ".addresses";
+ pollOnce();
+
+ Assert.assertEquals((Object) scoreboard.get(tags[0]),
+ ConfigurationManager.getConfigInstance().getList(firstKey).size());
+ Assert.assertEquals((Object) scoreboard.get(tags[1]),
+ ConfigurationManager.getConfigInstance().getList(secondKey).size());
+ }
+}
Oops, something went wrong.

0 comments on commit 940358f

Please sign in to comment.