Skip to content

Commit

Permalink
Merge pull request #104 from cfg4j/builders
Browse files Browse the repository at this point in the history
Add source builders and limit access to configuration source classes
  • Loading branch information
norbertpotocki committed Aug 8, 2015
2 parents 2a044ca + 5bdaaca commit 3754866
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,47 +24,42 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class ConsulConfigurationSource implements ConfigurationSource {
/**
* Note: use {@link ConsulConfigurationSourceBuilder} for building instances of this class.
* <p>
* Read configuration from the Consul K-V store.
*/
class ConsulConfigurationSource implements ConfigurationSource {

private static final Logger LOG = LoggerFactory.getLogger(ConsulConfigurationSource.class);

/**
* Default Consul HTTP API host.
*/
public static final String DEFAULT_HTTP_HOST = "localhost";

/**
* Default Consul HTTP API port.
*/
public static final int DEFAULT_HTTP_PORT = 8500;

private final KeyValueClient kvClient;
private Map<String, String> consulValues;

public ConsulConfigurationSource() {
this(DEFAULT_HTTP_HOST, DEFAULT_HTTP_PORT);
}

public ConsulConfigurationSource(URL url) {
this(url.getHost(), url.getPort());
}

private ConsulConfigurationSource(String host, int port) {
/**
* Note: use {@link ConsulConfigurationSourceBuilder} for building instances of this class.
* <p>
* Read configuration from the Consul K-V store located at {@code host}:{@code port}.
*
* @param host Consul host to connect to
* @param port Consul port to connect to
* @throws SourceCommunicationException when unable to connect to Consul client
*/
ConsulConfigurationSource(String host, int port) {
try {
LOG.info("Connecting to Consul client at " + host + ":" + port);

Consul consul = Consul.newClient(host, port);
kvClient = consul.keyValueClient();
} catch (Exception e) {
throw new SourceCommunicationException("Can't connect to host: " + host + ":" + port, e);
throw new SourceCommunicationException("Can't connect to host " + host + ":" + port, e);
}

reload();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl)
*
* 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.cfg4j.source.consul;

/**
* Builder for {@link ConsulConfigurationSource}.
*/
public class ConsulConfigurationSourceBuilder {

private String host;
private int port;

/**
* Construct {@link ConsulConfigurationSource}s builder
* <p>
* Default setup (override using with*() methods)
* <ul>
* <li>host: localhost</li>
* <li>port: 8500</li>
* </ul>
*/
public ConsulConfigurationSourceBuilder() {
host = "localhost";
port = 8500;
}

/**
* Set Consul host for {@link ConsulConfigurationSource}s built by this builder.
*
* @param host host to use
* @return this builder with Consul host set to provided parameter
*/
public ConsulConfigurationSourceBuilder withHost(String host) {
this.host = host;
return this;
}

/**
* Set Consul port for {@link ConsulConfigurationSource}s built by this builder.
*
* @param port port to use
* @return this builder with Consul port set to provided parameter
*/
public ConsulConfigurationSourceBuilder withPort(int port) {
this.port = port;
return this;
}

/**
* Build a {@link ConsulConfigurationSource} using this builder's configuration
*
* @return new {@link ConsulConfigurationSource}
*/
public ConsulConfigurationSource build() {
return new ConsulConfigurationSource(host, port);
}

@Override
public String toString() {
return "ConsulConfigurationSource{" +
"host=" + host +
", port=" + port +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;


Expand Down Expand Up @@ -83,27 +82,20 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio
@Before
public void setUp() throws Exception {
dispatcher = new ModifiableDispatcher();
runMockServerOnPort(ConsulConfigurationSource.DEFAULT_HTTP_PORT);
source = new ConsulConfigurationSource(server.getUrl(""));
runMockServer();
source = new ConsulConfigurationSourceBuilder()
.withHost(server.getHostName())
.withPort(server.getPort())
.build();
}

@After
public void tearDown() throws Exception {
server.shutdown();
}

@Test
public void shouldConnectToLocalhostAgentByDefault() throws Exception {
source = new ConsulConfigurationSource();
RecordedRequest request = server.takeRequest(0, TimeUnit.MILLISECONDS);
assertThat(request).isNotNull();
}

@Test
public void shouldConnectToSpecifiedAgent() throws Exception {
server.shutdown();
runMockServerOnPort(ConsulConfigurationSource.DEFAULT_HTTP_PORT + 1);
source = new ConsulConfigurationSource(new URL("http", "localhost", ConsulConfigurationSource.DEFAULT_HTTP_PORT + 1, ""));
RecordedRequest request = server.takeRequest(0, TimeUnit.MILLISECONDS);
assertThat(request).isNotNull();
}
Expand All @@ -112,31 +104,28 @@ public void shouldConnectToSpecifiedAgent() throws Exception {
public void shouldThrowOnConnectionFailure() throws Exception {
server.shutdown();
expectedException.expect(SourceCommunicationException.class);
source = new ConsulConfigurationSource();
}

@Test
public void shouldThrowOnConnectionFailure2() throws Exception {
expectedException.expect(SourceCommunicationException.class);
source = new ConsulConfigurationSource(new URL("http", "localhost", ConsulConfigurationSource.DEFAULT_HTTP_PORT + 1, ""));
source = new ConsulConfigurationSourceBuilder()
.withHost(server.getHostName())
.withPort(server.getPort())
.build();
}

@Test
public void getConfiguration2ShouldReturnAllKeysFromGivenEnvironment() throws Exception {
public void getConfigurationShouldReturnAllKeysFromGivenEnvironment() throws Exception {
Environment environment = new ImmutableEnvironment("us-west-1");

assertThat(source.getConfiguration(environment)).contains(MapEntry.entry("featureA.toggle", "disabled"));
}

@Test
public void getConfiguration2ShouldIgnoreLeadginSlashInGivenEnvironment() throws Exception {
public void getConfigurationShouldIgnoreLeadginSlashInGivenEnvironment() throws Exception {
Environment environment = new ImmutableEnvironment("/us-west-1");

assertThat(source.getConfiguration(environment)).contains(MapEntry.entry("featureA.toggle", "disabled"));
}

@Test
public void getConfiguration2ShouldBeUpdatedByReload() throws Exception {
public void getConfigurationShouldBeUpdatedByReload() throws Exception {
dispatcher.toggleUsWest2();

source.reload();
Expand All @@ -152,9 +141,9 @@ public void reloadShouldThrowOnConnectionFailure() throws Exception {
source.reload();
}

private void runMockServerOnPort(int port) throws IOException {
private void runMockServer() throws IOException {
server = new MockWebServer();
server.setDispatcher(dispatcher);
server.start(port);
server.start(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,21 @@
import java.util.Properties;

/**
* Basic implementation of {@link ConfigurationProvider}
* Basic implementation of {@link ConfigurationProvider}. To construct this provider use {@link ConfigurationProviderBuilder}.
*/
public class SimpleConfigurationProvider implements ConfigurationProvider {
class SimpleConfigurationProvider implements ConfigurationProvider {

private final ConfigurationSource configurationSource;
private final Environment environment;

/**
* {@link ConfigurationProvider} backed by provided {@link ConfigurationSource} and using {@code environment}
* to select environment.
* to select environment. To construct this provider use {@link ConfigurationProviderBuilder}.
*
* @param configurationSource source for configuration
* @param environment {@link Environment} to use
* @param environment {@link Environment} to use
*/
public SimpleConfigurationProvider(ConfigurationSource configurationSource, Environment environment) {
SimpleConfigurationProvider(ConfigurationSource configurationSource, Environment environment) {
this.configurationSource = requireNonNull(configurationSource);
this.environment = requireNonNull(environment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class GitConfigurationSource implements ConfigurationSource, Closeable {
/**
* Note: use {@link GitConfigurationSourceBuilder} for building instances of this class.
* <p>
* Read configuration from the remote GIT repository. Keeps a local clone of the repository.
*/
class GitConfigurationSource implements ConfigurationSource, Closeable {

private static final Logger LOG = LoggerFactory.getLogger(GitConfigurationSource.class);

Expand Down

0 comments on commit 3754866

Please sign in to comment.