Configuration abstraction framework using Google Protocol Buffers, Spring and varous formatters
Java Shell Groovy
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
gradle/wrapper
src
.gitignore
LICENSE-2.0
NOTICE
README.md
build.gradle
build.sh
config-protobuf-spring-java.iml
gradlew
gradlew.bat

README.md

Configuration abstraction framework using Google Protocol Buffers, Spring and varous formatters

Concepts

Configuration framework is designed to provide separation between config consumption and aquisition. The consumer package provides interfaces that should be coded against by the application wishing to consume the config data. The data is returned in the form of Google Protocol Buffers Message objects which have been populated from various dedicated or augmenting sources (HTTP, Files, DB, etc) stored in various formats (XML, JSON, Properties, Protobuf Binary, etc). The provider package provides interfaces that should be coded against by the config data retrieval providers and formatters. The responsibility of actually interpreting the ConfigParam elements and deciding on where to load the actual config data from and what format conversion to use falls upon the jurisdiction of ConfigProvider implementations.

Formats

The framework uses Protobuf Java Format library for converting XML, JSON, Text and Properties files into Protocol Buffers Messages. AbstractConfigProvider provides a convertMessage function that is handling the conversion from the above-mentioned formats.

Usage

API

ConfigClient

Configuration framework provides a main entry class into the configuration system - ConfigClient. The ConfigClient interface should be implemented by any class wishing to provide access to config. The default implementation of ConfigClient provided by this framework is the ProviderBasedConfigClient.

ConfigProvider

ConfigProvider interface is geared to provide the abstraction and a separation from the config consumption and the actual retrieval of config data.

ResourceConfigProvider

Provides functionality to load config files out of Spring's Resource class, which usually represents any file system or a classpath resource. It uses file type extension to infer content type. i.e. .xml => XML, .json => JSON, etc.

HttpConfigProvider

Uses Apache HttpClient to retrieve the config resources from any HTTP/S endpoint.

ConfigParamsBuilder

ConfigParamsBuilder is a builder class that is designed to aid in the rapid-chain-creation of the named config parameters map to be supplied to the ConfigClient instance to retrieve the desired config.

ConfigClientInvocationHandler

ConfigClientInvocationHandler is an implementation of the Java Dynamic Proxy Invocation Handler to aid in the effort of making config consumption look and feel just like making any other service call. It utilizes the ConfigParam method argument annotation to be placed on the config interface definitions which will later be used to construct the ConfigParamsMap and passed to the underlying ConfigClient delegate along with the return Message type which is derived from the return type specified on the config interface.

ConfigClientFactoryBean

For the Spring users (which you all should be) a ConfigClientFactoryBean is provided to ease the creation of the dynamic proxy for the supplied config interface and ConfigClient.

Example

Let's imagine that we have the following Protocol Buffers definition for our config data model:

config.proto

package test.config;

option java_package = "ws.antonov.config.test.proto.model";
option java_outer_classname = "TestProtos";
option java_multiple_files = true;

option optimize_for = SPEED;

message FlatConfigObject {
    optional int32 timeout = 1;
    optional bool validate = 2;
    optional string system_code = 3;
}

as well as the following config interface defined:

FlatConfigService.java

package ws.antonov.config.consumer;

import ws.antonov.config.api.consumer.ConfigParam;
import ws.antonov.config.test.proto.model.FlatConfigObject;

/**
 */
public interface FlatConfigService {
    public FlatConfigObject getConfig(@ConfigParam("domain") String domain,
                                      @ConfigParam("path") String path);
}

The definition of your Spring ApplicationContext.xml would be:

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>

    <bean id="configProvider" class="ws.antonov.config.provider.ResourceConfigProvider">
        <constructor-arg value="file://${user.dir}"/> <!-- Base Dir -->
        <constructor-arg value="/{domain}/{path}"/> <!-- ConfigParam name matching pattern -->
    </bean>

    <bean id="configClient" class="ws.antonov.config.consumer.ProviderBasedConfigClient">
        <constructor-arg ref="configProvider"/>
    </bean>

    <bean id="configService" class="ws.antonov.config.api.consumer.ConfigClientFactoryBean">
        <constructor-arg value="ws.antonov.config.consumer.FlatConfigService"/>
        <constructor-arg ref="configClient"/>
    </bean>
</beans>

The resulting configService bean can be used to wire in the FlatConfigService object as a dependency into any other class you have in your application context.

Let's say that our configuration is stored in a properties file:

config.properties

timeout=10
validate=false
system_code="101"

The application code would consume it the following way:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
FlatConfigService service = context.getBean(FlatConfigService.class);
FlatConfigObject config = service.getConfig("build/classes", "test/config.properties");

Of course, in your real application you would not couple the underlying file storage/location with the business logic, so the parameters you would pass in into the config service would be something along the lines of a business domain ('search', 'purchase', etc), or let's say a Locale ('en_US') as a separator. The rest of the path would be hard-coded in your Spring file: /config_files/{locale}/{domain}.properties. The pattern resolution is handled by Spring's UriTemplate.

One other ability is to provide your own facade around the ConfigProvider which would add some implicit config param values to the map, things like application id (if one exists) or a machine IP, or anything that can be passed in as a -D start-up property.