An open API service indexing awesome lists of open source software.

https://github.com/teragrep/cnf_01

Teragrep Configuration Library for Java
https://github.com/teragrep/cnf_01

config configuration java java-library library teragrep

Last synced: 28 days ago
JSON representation

Teragrep Configuration Library for Java

Awesome Lists containing this project

README

        

// Before publishing your new repository:
// 1. Write the readme file
// 2. Update the issues link in Contributing section in the readme file
// 3. Update the discussion link in config.yml file in .github/ISSUE_TEMPLATE directory

= Teragrep Configuration Library for Java

// Add a short description of your project. Tell what your project does and what it's used for.

CNF-01 is a library that provides immutable configuration for Java projects. Immutability is achieved by converting the configuration source into an immutable Map. The resulting configuration Map can't be altered even with modifying the underlying source.

== Features

// List your project's features
- Provides immutable configurations for:
. configuration files / path properties (`PathConfiguration`)
. System Properties (`PropertiesConfiguration`)
. environment variables (`EnvironmentConfiguration`)
. command line arguments (`ArgsConfiguration`)
- Default configurations in case the provided configurations from a source are not found or are otherwise broken (`DefaultConfiguration`)

== A Word About Immutability

Notable in CNF-01 is that the *configurations can not change after initialization*.

For example, something might be added to the Java's System Properties even before calling `asMap()` on the `PropertiesConfiguration` object. However, this will not have effect on the `Configuration` object at all. *All the objects are immutable.*

== How To Implement

When implementing CNF-01 to a project, the point is to keep the main objects immutable and simple by moving the handling of configuration to their own objects.

Follow these steps to implement CNF-01 in a Java project:

* Identify the object that has to use configurations.
* You can define an interface for the factory objects that create the configured objects:
+

[,java]
----
public interface Factory {
public T object();
}
----

* Create a Factory object for the object that has to use configurations.
+

[,java]
----
public final class ExampleFactory implements Factory {

private final Map config;

public ExampleFactory(final Map config) {
this.config = config;
}

@Override
public Example object() {
// Parsing of values should be done here too if something else than String is needed
final String exampleType = config.get("example.type");
final String exampleText = config.get("example.text");
final Example example;

if (exampleType.equals("good")) {
example = new GoodExample(exampleText);
} else {
example = new BadExample(exampleText);
}

return example;
}
}
----

* Utilize the Factory object to get properly initialized objects with the configuration options.
+

[,java]
----
PropertiesConfiguration config = new PropertiesConfiguration();
Map configurationMap = config.asMap();

ExampleFactory exampleFactory = new ExampleFactory(configurationMap);
Example example = exampleFactory.object();
----

* Create additional factories for other objects that require configurations.

== How To Use

// add instructions how people can start to use your project
=== Configuration

All the sources are usable with the same `Configuration` -interface. It has a single function:

[,java]
----
Map asMap() throws ConfigurationException;
----

=== System Properties

In Java, System properties can be utilized with `System.setProperty(key, value)`.

System properties can be used as a configuration source in CNF-01 with the `PropertiesConfiguration` object. It has two constructors:

[,java]
----
public PropertiesConfiguration(); // uses System.getProperties()
public PropertiesConfiguration(Properties properties); // uses any Java Properties given
----

Most likely the default constructor is what you'll need, but in some cases the second constructor might become handy.

Here's an example of using `PropertiesConfiguration`:

[,java]
----
PropertiesConfiguration config = new PropertiesConfiguration(); // uses System.getProperties()
Map result = config.asMap();
----

=== Configuration File

One of the supported configuration sources is a `File`. These are often marked with a ".properties" file extension but basically any Java's `File` object will do. The properties have to be given in a `key=value` format in the `File`. For example:

[,bash]
----
bar=foo
foo=bar
----

A file can be used as a configuration source with the `PathConfiguration` object. It has two constructors:

[,java]
----
public PathConfiguration(final String fileName); // Uses the filename
public PathConfiguration(final File file); // Uses Java's File object
----

Here's an example of using `PathConfiguration`:

[,java]
----
Configuration configuration = new PathConfiguration("file/path");
Map configMap = new HashMap<>();
try {
configMap = configuration.asMap();
} catch (ConfigurationException e) {
// Handle the exception...
}
----

`PathConfiguration` throws an exception if the `File` is not found.

Read Default Configuration section to see how default configurations can be used to avert the need for the try-catch.

=== Command Line Arguments

Command line arguments (or any `String[] args`) can be utilized as a configuration source with the `ArgsConfiguration` object.

Here's an example of using `ArgsConfiguration`:

[,java]
----
public static void main(String[] args) {
Configuration configuration = new ArgsConfiguration(args);
Map configMap = new HashMap<>();
try {
configMap = configuration.asMap();
} catch (ConfigurationException e) {
// Handle the exception...
}
}
----

`ArgsConfiguration` throws an exception if the Strings in the array don't follow the `key=value` format.

Read Default Configuration section to see how default configurations can be used to avert the need for the try-catch.

=== Environment Variables

`EnvironmentConfiguration` object supports Java's `System.getenv()`, meaning the system's environment variables. The constructor takes no arguments.

Here's an example of using `EnvironmentConfiguration`:

[,java]
----
Configuration configuration = new EnvironmentConfiguration();
Map configMap = configuration.asMap();
----

=== Default Configuration

Default configurations can be used in case the `asMap()` function throws `ConfigurationException`. If the function throws an exception, the defaults are used instead. Only `PathConfiguration` and `ArgsConfiguration` can currently throw an exception.

`DefaultConfiguration` follows the pattern of composable decorators introduced in Elegant Objects. Therefore, it takes another `Configuration` object as an argument in the constructor. The second argument is an `ImmutableMap` which is in the CNF-01 library as well.

Here's an example of how to use `DefaultConfiguration` when paired with `PathConfiguration`:

[,java]
----
Map map = new HashMap<>();
map.put("foo", "bar");
ImmutableMap defaults = new ImmutabilitySupportedMap<>(map).toImmutableMap();

DefaultConfiguration defaultConfiguration = new DefaultConfiguration(
new PathConfiguration("invalid.path"), // uses PathConfiguration that will throw an exception
defaults
);

Map result = defaultConfiguration.asMap();
----

== Contributing

// Change the repository name in the issues link to match with your project's name

You can involve yourself with our project by https://github.com/teragrep/cnf_01/issues/new/choose[opening an issue] or submitting a pull request.

Contribution requirements:

. *All changes must be accompanied by a new or changed test.* If you think testing is not required in your pull request, include a sufficient explanation as why you think so.
. Security checks must pass
. Pull requests must align with the principles and http://www.extremeprogramming.org/values.html[values] of extreme programming.
. Pull requests must follow the principles of Object Thinking and Elegant Objects (EO).

Read more in our https://github.com/teragrep/teragrep/blob/main/contributing.adoc[Contributing Guideline].

=== Contributor License Agreement

Contributors must sign https://github.com/teragrep/teragrep/blob/main/cla.adoc[Teragrep Contributor License Agreement] before a pull request is accepted to organization's repositories.

You need to submit the CLA only once. After submitting the CLA you can contribute to all Teragrep's repositories.