BetterConfig Java Client

BetterConfig Java client library.

License

License

Categories

Categories

CLI User Interface config Application Layer Libs Configuration
GroupId

GroupId

com.betterconfig
ArtifactId

ArtifactId

betterconfig-client
Last Version

Last Version

1.1.1
Release Date

Release Date

Type

Type

jar
Description

Description

BetterConfig Java Client
BetterConfig Java client library.
Project URL

Project URL

https://github.com/betterconfig/betterconfigclient-java
Project Organization

Project Organization

BetterConfig
Source Code Management

Source Code Management

https://github.com/betterconfig/betterconfigclient-java

Download betterconfig-client

How to add to project

<!-- https://jarcasting.com/artifacts/com.betterconfig/betterconfig-client/ -->
<dependency>
    <groupId>com.betterconfig</groupId>
    <artifactId>betterconfig-client</artifactId>
    <version>1.1.1</version>
</dependency>
// https://jarcasting.com/artifacts/com.betterconfig/betterconfig-client/
implementation 'com.betterconfig:betterconfig-client:1.1.1'
// https://jarcasting.com/artifacts/com.betterconfig/betterconfig-client/
implementation ("com.betterconfig:betterconfig-client:1.1.1")
'com.betterconfig:betterconfig-client:jar:1.1.1'
<dependency org="com.betterconfig" name="betterconfig-client" rev="1.1.1">
  <artifact name="betterconfig-client" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.betterconfig', module='betterconfig-client', version='1.1.1')
)
libraryDependencies += "com.betterconfig" % "betterconfig-client" % "1.1.1"
[com.betterconfig/betterconfig-client "1.1.1"]

Dependencies

compile (3)

Group / Artifact Type Version
com.squareup.okhttp3 : okhttp jar 3.9.1
org.slf4j : slf4j-api jar 1.7.25
com.google.code.gson : gson jar 2.8.2

Project Modules

There are no modules declared in this project.

BetterConfig client for Java

BetterConfig is a cloud based configuration as a service. It integrates with your apps, backends, websites, and other programs, so you can configure them through this website even after they are deployed.

Build Status Maven Central Coverage Status Javadocs

Getting started

1. Add the package to your project

Maven:

<dependency>
    <groupId>com.betterconfig</groupId>
    <artifactId>betterconfig-client</artifactId>
    <version>1.1.1</version>
</dependency>

Gradle:

compile 'com.betterconfig:betterconfig-client:1.1.1'

2. Get your Project Secret from BetterConfig.com portal YourConnectionUrl

3. Import the BetterConfig package

import com.betterconfig.*;

4. Create a BetterConfigClient instance

BetterConfigClient client = new BetterConfigClient("<PLACE-YOUR-PROJECT-SECRET-HERE>");

5. Get your config value

boolean isMyAwesomeFeatureEnabled = client.getValue(Boolean.class, "key-of-my-awesome-feature", false);
if(isMyAwesomeFeatureEnabled) {
    //show your awesome feature to the world!
}

Or use the async APIs:

client.getValueAsync(Boolean.class, "key-of-my-awesome-feature", false)
    .thenAccept(isMyAwesomeFeatureEnabled -> {
        if(isMyAwesomeFeatureEnabled) {
            //show your awesome feature to the world!
        }
    });

Android

The minimum supported sdk version is 26 (oreo). Java 1.8 or later is required.

android {
    defaultConfig {
        //...
        minSdkVersion 26
    }
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

You also have to put this line into your manifest xml to enable the library access to the network.

<uses-permission android:name="android.permission.INTERNET" />

Configuration

HttpClient

The BetterConfig client internally uses an OkHttpClient instance to fetch the latest configuration over HTTP. You have the option to override the internal HttpClient with your customized one. For example if your application runs behind a proxy you can do the following:

Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyHost", proxyPort));

BetterConfigClient client = BetterConfigClient.newBuilder()
                .httpClient(new OkHttpClient.Builder()
                            .proxy(proxy)
                            .build())
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

As the BetterConfig client maintains the whole lifetime of the internal HttpClient, it's being closed simultaneously with the BetterConfig client, refrain from closing the HttpClient manually.

Refresh policies

The internal caching control and the communication between the client and BetterConfig are managed through a refresh policy. There are 3 predefined implementations built in the library.

1. Auto polling policy (default)

This policy fetches the latest configuration and updates the cache repeatedly.

Poll interval

You have the option to configure the polling interval through its builder (it has to be greater than 2 seconds, the default is 60):

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> 
                    AutoPollingPolicy.newBuilder()
                        .autoPollIntervalInSeconds(120) // set the polling interval
                        .build(configFetcher, cache)
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");
Change listeners

You can set change listeners that will be notified when a new configuration is fetched. The policy calls the listeners only, when the new configuration is differs from the cached one.

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> 
                    AutoPollingPolicy.newBuilder()
                        .configurationChangeListener((parser, newConfiguration) -> {
                            // here you can parse the new configuration like this: 
                            // parser.parseValue(Boolean.class, newConfiguration, "key-of-my-awesome-feature")                            
                        })
                        .build(configFetcher, cache)
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

If you want to subscribe to the configuration changed event later in your applications lifetime, then you can do the following (this will only work when you have an auto polling refresh policy configured in the BetterConfig client):

client.getRefreshPolicy(AutoPollingPolicy.class)
    .addConfigurationChangeListener((parser, newConfiguration) -> {
        // here you can parse the new configuration like this: 
        // parser.parseValue(Boolean.class, newConfiguration, "key-of-my-awesome-feature")  
    });

You can check this in action in the Android sample.

2. Expiring cache policy

This policy uses an expiring cache to maintain the internally stored configuration.

Cache refresh interval

You can define the refresh rate of the cache in seconds, after the initial cached value is set this value will be used to determine how much time must pass before initiating a new configuration fetch request through the ConfigFetcher.

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> 
                    ExpiringCachePolicy.newBuilder()
                        .cacheRefreshIntervalInSeconds(120) // the cache will expire in 120 seconds
                        .build(configFetcher, cache)
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");
Async / Sync refresh

You can define how do you want to handle the expiration of the cached configuration. If you choose asynchronous refresh then when a request is being made on the cache while it's expired, the previous value will be returned immediately until the fetching of the new configuration is completed.

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> 
                    ExpiringCachePolicy.newBuilder()
                        .asyncRefresh(true) // the refresh will be executed asynchronously
                        .build(configFetcher, cache)
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

If you set the .asyncRefresh() to be false, the refresh operation will be awaited until the fetching of the new configuration is completed.

3. Manual polling policy

With this policy every new configuration request on the BetterConfigClient will trigger a new fetch over HTTP.

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> new ManualPollingPolicy(configFetcher,cache));

Custom Policy

You can also implement your custom refresh policy by extending the RefreshPolicy abstract class.

public class MyCustomPolicy extends RefreshPolicy {
    
    public MyCustomPolicy(ConfigFetcher configFetcher, ConfigCache cache) {
        super(configFetcher, cache);
    }

    @Override
    public CompletableFuture<String> getConfigurationJsonAsync() {
        // this method will be called when the configuration is requested from the BetterConfig client.
        // you can access the config fetcher through the super.fetcher() and the internal cache via super.cache()
    }
    
    // optional, in case if you have any resources that should be closed
    @Override
     public void close() throws IOException {
        super.close();
        // here you can close your resources
    }
}

If you decide to override the close() method, you also have to call the super.close() to tear down the policy appropriately.

Then you can simply inject your custom policy implementation into the BetterConfig client:

BetterConfigClient client = BetterConfigClient.newBuilder()
                .refreshPolicy((configFetcher, cache) -> new MyCustomPolicy(configFetcher, cache)) // inject your custom policy
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

Custom Cache

You have the option to inject your custom cache implementation into the client. All you have to do is to inherit from the ConfigCache abstract class:

public class MyCustomCache extends ConfigCache {
    
    @Override
    public String read() {
        // here you have to return with the cached value
        // you can access the latest cached value in case 
        // of a failure like: super.inMemoryValue();
    }

    @Override
    public void write(String value) {
        // here you have to store the new value in the cache
    }
}

Then use your custom cache implementation:

BetterConfigClient client = BetterConfigClient.newBuilder()
                .cache(new MyCustomCache()) // inject your custom cache
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

Maximum wait time for synchronous calls

You have the option to set a timeout value for the synchronous methods of the library (getConfigurationJsonString(), getConfiguration(), getValue() etc.) which means when a sync call takes longer than the timeout value, it'll return with the default.

BetterConfigClient client = BetterConfigClient.newBuilder()
                .maxWaitTimeForSyncCallsInSeconds(2) // set the max wait time
                .build("<PLACE-YOUR-PROJECT-SECRET-HERE>");

Force refresh

Any time you want to refresh the cached configuration with the latest one, you can call the forceRefresh() method of the library, which will initiate a new fetch and will update the local cache.

Logging

The BetterConfig client uses the facade of slf4j for logging.

Samples

Versions

Version
1.1.1
1.1.0
1.0.5
1.0.4