Skip to content
Browse files

Merge pull request #25 from racker/move_archaius_bindings_here

Move archaius bindings here
  • Loading branch information...
2 parents 5626904 + 36a0a32 commit efb95af8bc091711da46e8727b754e0aeabda521 @Kami Kami committed
View
22 README.md
@@ -1,10 +1,10 @@
-# Java Rackspace Service Registry client
+# Java Rackspace Service Registry Client
Java client for Rackspace Service Registry.
## Build and run tests
- mvn install
+ mvn install
## Using the client
@@ -27,12 +27,12 @@ Add the following lines in the `repositories` and `dependencies` section in your
If you're using ivy, this needs to be in your ivysettings.xml:
```xml
- <ibiblio name="sonatype"
- m2compatible="true"
+ <ibiblio name="sonatype"
+ m2compatible="true"
usepoms="true"
root="https://oss.sonatype.org/content/repositories/snapshots/"
pattern="[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
- changingPattern="SNAPSHOT*"/>
+ changingPattern="SNAPSHOT*"/>
```
This lines are necessary because artifacts are currently only stored on Sonatype staging Maven servers.
@@ -56,10 +56,18 @@ Released versions of the library are integrated into Maven Central. There is no
<groupId>com.rackspacecloud</groupId>
<artifactId>service-registry-client</artifactId>
<version>1.0.0</version>
- </dependency>
+ </dependency>
```
-Other modules you may be interested in include `service-registry-curator` and `service-registry-examples`.
+### Other Modules
+
+This repository also includes other modules:
+
+`service-registry-curator` - Service Registry bindings for Netflix Curator
+library
+`service-registry-archaius` - Service Registry bindings for Netflix Archaius
+library
+`service-registry-examples` - Usage examples
### Examples
View
1 pom.xml
@@ -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>
View
25 service-registry-archaius/README.md
@@ -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
View
79 service-registry-archaius/pom.xml
@@ -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>2.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>
View
12 ...ice-registry-archaius/src/main/java/com/netflix/config/sources/ServiceRegistryClient.java
@@ -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;
+}
View
25 ...stry-archaius/src/main/java/com/netflix/config/sources/ServiceRegistryClientProvider.java
@@ -0,0 +1,25 @@
+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.getServicesClient().list(null, tag);
+ }
+
+ @Override
+ public List<ConfigurationValue> getConfiguration() throws Exception {
+ return client.getConfigurationClient().list(null);
+ }
+}
View
93 ...chaius/src/main/java/com/netflix/config/sources/ServiceRegistryConfigurationProvider.java
@@ -0,0 +1,93 @@
+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)) {
+ InetSocketAddress pair = getHostPortPair(service);
+
+ if (pair != null) {
+ pairs.add(pair);
+ }
+ }
+
+ 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;
+ }
+}
View
134 ...c/test/java/com/netflix/config/sources/test/ServiceRegistryConfigurationProviderTest.java
@@ -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, 15, 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, 15, 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());
+ }
+}
View
40 ...c/test/java/com/netflix/config/sources/test/TestServiceRegistryConfigurationProvider.java
@@ -0,0 +1,40 @@
+package com.netflix.config.sources.test;
+
+import com.netflix.config.sources.ServiceRegistryClient;
+import com.rackspacecloud.client.service_registry.objects.ConfigurationValue;
+import com.rackspacecloud.client.service_registry.objects.Service;
+
+import java.util.*;
+
+public class TestServiceRegistryConfigurationProvider implements ServiceRegistryClient {
+
+ Map<String, List<Service>> services = new HashMap<String, List<Service>>();
+ List<ConfigurationValue> configurationValues = new ArrayList<ConfigurationValue>();
+
+ public void addService(String tag, Service svc) {
+ List<Service> svcs = services.get(tag);
+ if (svcs == null) {
+ svcs = new ArrayList<Service>();
+ }
+ svcs.add(svc);
+ services.put(tag, svcs);
+ }
+
+ public void addConfigurationValue(ConfigurationValue cfg) {
+ configurationValues.add(cfg);
+ }
+
+ @Override
+ public List<Service> getServices(String tag) throws Exception {
+ List<Service> result = services.get(tag);
+ if (result == null) {
+ return Collections.emptyList();
+ }
+ return result;
+ }
+
+ @Override
+ public List<ConfigurationValue> getConfiguration() throws Exception {
+ return configurationValues;
+ }
+}
View
1 service-registry-archaius/src/test/resources/config.properties
@@ -0,0 +1 @@
+test.more="foo"
View
11 service-registry-archaius/src/test/resources/logback-test.xml
@@ -0,0 +1,11 @@
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <outputPatternAsHeader>false</outputPatternAsHeader>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+ <root level="info">
+ <appender-ref ref="STDOUT"/>
+ </root>
+</configuration>

0 comments on commit efb95af

Please sign in to comment.
Something went wrong with that request. Please try again.