Skip to content

Commit

Permalink
Merge pull request #5 from TechnologyBrewery/KRAUS-16
Browse files Browse the repository at this point in the history
KRAUS-16: 📝 clean up entry documentation to not be all Java with…
  • Loading branch information
d-ryan-ashcraft authored Apr 18, 2023
2 parents 640e0bd + 2e6612b commit c1d37ef
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 280 deletions.
49 changes: 1 addition & 48 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,51 +44,4 @@ Krausening uses both the `maven-release-plugin` and the `nexus-staging-maven-plu
export GPG_TTY=`tty`;
```

5. Execute `mvn release:clean release:prepare`, answer the prompts for the versions and tags, and perform `mvn release:perform`

## Krausening Architecture (Java)

It is worth first noting that many of the classes and interfaces defined in the source code rely on the [org.aeonbits.owner package](http://owner.aeonbits.org/docs/usage/). Below is a summary of the Krausening source code's files.

```
org
├── aeonbit/owner
│ └── ExtendedKrauseningSource.java
│ └── KrauseningAwarePropertiesManager.java
│ └── KrauseningConfig.java
│ └── KrauseningConfigFactory.java
│ └── KrauseningFactory.java
|
├── bitbucket/krausening
| └── Krausening.java
| └── KrauseningException.java
| └── KrauseningWarSpecificBootstrapContextListener.java
```

#### org.aeonbit.owner
* ```ExtendedKrauseningSource.java```
* Provides a consistent mechanism to extend a KrauseningSources annotated config class by overwriting the properties file name to something new at runtime.
* The primary use case for this functionality is when you want to build some generic code and need to have multiple different property sets for the same concept deployed at the same time.
* ```KrauseningAwarePropertiesManager.java```
* KrauseningAwarePropertiesManager replaces the default URL-based property file specification strategy that is implemented in PropertiesManager and delegates to Krausening for loading property files.
* All of the features present in OWNER, such as property variable expansion, default property values, hot reloading property files, etc. are still supported.
* In addition, developers may still use the Config.Sources annotation in conjunction with the KrauseningConfig.KrauseningSources annotation on the same interface in order to load *.properties with Krausening and *.xml properties using OWNER.
* ```KrauseningConfig.java```
* KrauseningConfig serves as the interface to extend in order to define a property mapping interface.
* Annotations that are used to specify the desired Krausening property files to load and merge policy are also encapsulated within this interface.
* ```KrauseningConfigFactory.java```
* KrauseningConfigFactory is largely modeled after ConfigFactory and provides a simple, straightforward adapter for creating KrauseningConfig proxies and largely delegates to an underlying KrauseningFactory implementation.
* This class is the intended and expected entry point for creating KrauseningConfig proxies.
* ```KrauseningFactory.java```
* KrauseningFactory extends DefaultFactory in order to delegate to KrauseningAwarePropertiesManager for property mapper proxy generation.

#### org.technologybrewery.krausening
* ```Krausening.java```
* Krausening serves as the entry singleton, which reads the specified properties files (through Java System Properties)
* The first base properties will be loaded, with anything in the extensions location being added on to the top. This allows value to be added or overridden, which is especially useful when you have a standard configuration defined in your base files, but need to specialize some values for different deployments.
* Only .properties files will be loaded. Any other file encountered will be skipped.
* ```KrauseningException.java```
* KrauseningException extends RuntimeException
* Krausening library's custom exception
* ```KrauseningWarSpecificBootstrapContextListener.java```
* KrauseningWarSpecificBootstrapContextListener serves to initilize and destroy ServletContextListeners when OVERRIDE_EXTENSIONS_SUBFOLDER_PARAM is defined
5. Execute `mvn release:clean release:prepare`, answer the prompts for the versions and tags, and perform `mvn release:perform`
228 changes: 12 additions & 216 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,235 +5,31 @@
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/krausening)
![PyPI - Wheel](https://img.shields.io/pypi/wheel/krausening)

In brewing, krausening (KROI-zen-ing) refers to adding a small amount of existing beer to fresh wort to prime the beer for carbonation. In Java, Krausening is a project to populate finished archives for deployment. This approach allows Properties files to be externalized from deployment units, enabling the same deployment unit to be leveraged repeatedly without the need to rebuild or hack the archive.
In brewing, krausening (KROI-zen-ing) refers to adding a small amount of existing beer to fresh wort to
prime the beer for carbonation. In technology, Krausening is a project to populate finished archives for
deployment. This approach allows configuration properties to be externalized from deployment units,
enabling the same deployment unit to be leveraged repeatedly without the need to rebuild or hack the
archive.

# Requirements
In order to use Krausening, the following prerequisites must be installed:

* Maven 3.6+
* Java 8+
* Java 11+

For [Krausening Python](https://bitbucket.org/cpointe/krausening/src/dev/krausening-python/), the following must also be installed:
For [Krausening Python](https://github.com/TechnologyBrewery/krausening/tree/dev/krausening-python/), the following must also be installed:

* [Poetry 1.1+](https://python-poetry.org/)
* [Poetry 1.2+](https://python-poetry.org/)
* [Pyenv](https://github.com/pyenv/pyenv)

# Krausening in One Pint (Learn Krausening in 2 Minutes)
Krausening is very simple. Follow these steps to prime your project:
# Krausening and Java

1. Add a Java System Property called KRAUSENING_BASE pointing to the folder with your .properties files
```properties
KRAUSENING_BASE=./src/test/resources/base
```
2. In your source code, get a handle to the Krausening singleton, then request the property file you'd like to access:
```java
Krausening krausening = Krausening.getInstance();
Properties properties = krausening.getProperties("example.properties");
See the [krausening README](https://github.com/TechnologyBrewery/krausening/tree/dev/krausening/) for more details.

```
3. You're done - order your next pint!

# Krausening in Two Pints (Leveraging Property Extension)
Often, some properties need to change as your deployment unit travels between environments. We want to do this without having to copy and paste all the properties, lowering our maintenance burden to just those properties that have changed. To accomplish this, build on the prior example by:

1. Add a Java System Property called KRAUSENING_EXTENSIONS pointing to the folder with your extension .properties files
```properties
KRAUSENING_EXTENSIONS=./src/test/resources/prod-env
```
2. Create a properties file of the same name as the one in base, only added the properties you want to extend:

```properties
# in $KRAUSENING_BASE/example.properties:
propertyA=org.org.technologybrewery.some.reflect.Class
propertyB=https://localhost/

# in $KRAUSENING_EXTENSIONS/example.properties:
propertyB=https://prodUrl/
```
3. When you look for your properties, you'll now get a collapsed version, containing propertyA from the base version, and propertyB from the extensions version:
```java
Krausening krausening = Krausening.getInstance();
Properties properties = krausening.getProperties("example.properties");
assertEquals(properties.get("propertyA"), "org.technologybrewery.some.reflect.Class");
assertEquals(properties.get("propertyB"), "https://prodUrl/");
```
4. You're done - try a mystery beer with Krausening's encryption integration to further quench your thirst.

# Krausening in Three Pints (Leveraging context specific properties)#
Sometimes different contexts/applications/classloads/wars want to have their own properties even when deployed in the same environments.
For example, foo and bar are deployed together with the same krausening base and extensions set, but _foo wants to have my.property=X and bar wants to have my.property=Y_.
In this case you can leverage override extensions to apply different properties per context.

1. Add a Java System Property called KRAUSENING_OVERRIDE_EXTENSIONS pointing to the folder with your override extension .properties files
```properties
KRAUSENING_OVERRIDE_EXTENSIONS=./src/test/resources/prod-env-overrides
```

2. Create subfolders for the different contexts you need to override extensions

```properties
# in $KRAUSENING_OVERRIDE_EXTENSIONS/foo/example.properties:
my.property=X

# in $KRAUSENING_OVERRIDE_EXTENSIONS/bar/example.properties:
my.property=Y
```

3. A) Update the web.xml files for each context to point to a different subfolder within the override extensions location

`web.xml` for foo
```xml
<listener>
<listener-class>org.technologybrewery.krausening.KrauseningWarSpecificBootstrapContextListener</listener-class>
</listener>
<context-param>
<param-name>override.extensions.subfolder</param-name>
<param-value>foo</param-value>
</context-param>
```

`web.xml` for bar (**NOTE the difference in the subfolder parameter**)
```xml
<listener>
<listener-class>org.technologybrewery.krausening.KrauseningWarSpecificBootstrapContextListener</listener-class>
</listener>
<context-param>
<param-name>override.extensions.subfolder</param-name>
<param-value>bar</param-value>
</context-param>
```
```java
Krausening krausening = Krausening.getInstance("foo");
Properties properties = krausening.getProperties("example.properties");
assertEquals(properties.get("my.property"), "X");
```


3. B) Alternatively, you can use an override subfolder when getting the krausening instance.

```java
Krausening krausening = Krausening.getInstance("foo");
Properties properties = krausening.getProperties("example.properties");
assertEquals(properties.get("my.property"), "X");
```

# Krausening in Four Pints (Leveraging Jasypt for Encrypting/Decrypting Properties)
Frequently, it is useful to store encrypted information within properties files. Krausening optionally leverages Jasypt to allow stored properties to be encrypted at rest while also decrypting property values as they are read without manual interaction.

1. Add a Java System Property called KRAUSENING_PASSWORD pointing to your Jasypt master encryption password.
```properties
KRAUSENING_PASSWORD=myMasterPassword
```

2. Use Jasypt to encrypt your property information with PBEWITHHMACSHA512ANDAES_256 algorithm

* 1- Download the [Jasypt CLI Tools](http://www.jasypt.org/cli.html)

* 2- Run the encrypt.sh to encrypt the password with following arguments
- **password**: The master password
- **input**: The content needs to be encrypted
- **algorithm**: Use `PBEWITHHMACSHA512ANDAES_256` for more secure encryption
- **ivGeneratorClassName**: Use `org.jasypt.iv.RandomIvGenerator`; this is needed to fix the jasypt bug (ref: https://github.com/jasypt/jasypt/issues/8)
```shell
./encrypt.sh \
password=myMasterPassword \
input=someStrongPassword \
algorithm=PBEWITHHMACSHA512ANDAES_256 \
ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator
```
* 3- Add the [encrypted value in your properties file via the Jasypt format](http://www.jasypt.org/encrypting-configuration.html):

```properties
password=ENC(cg6SE/H0moCnAg0suZwGKaZqguaemAQlf6RGU9NYfOdB+Q0MUtQsjfEVAkJS288n7wXXP1B6fEC9YqIYJM3dWw==)
```

3. When you look for your property, you'll now get the decrypted value:
```java
Krausening krausening = Krausening.getInstance();
krausening.loadProperties();
Properties properties = krausening.getProperties("encrypted.properties");
assertEquals(properties.get("password"), "someStrongPassword");
```
4. You're done - go for the whole sampler with Krausening's Owner integration if you're still thirsty.

# Krausening in Five Pints (Leveraging Owner Integration to Access Properties via Interfaces (and more))#
While accessing properties via `java.util.Properties` as `String` values works, wouldn't it be great if we could get compile-safe, strongly typed references to our Krausening property values that reflect their actual type? By integrating tightly with [Owner](http://owner.aeonbits.org/), Krausening can offer annotation-based type conversion, variable expansion, hot reloading, XML property file support, and all of the other great features that are built into Owner. Assuming that we have the following properties files created:
```properties
# in $KRAUSENING_BASE/example.properties:
fibonacci=1, 1, 2, 3, 5, 8
url=https://localhost
serviceSubPath=foo/baz
# in $KRAUSENING_EXTENSIONS/example.properties:
url=https://prodUrl
fullServiceUrl=${url}/${serviceSubPath}/endpoint
pi=3.1415
```
1. Create an interface that describes and maps to the contents of the collapsed version of `example.properties`. Code that relies on these property values will be able to directly use this interface, instead of interacting with a `java.util.Properties` object. The interface must contain a `@KrauseningSources` definition, along with any supported Owner annotation:
```java
@KrauseningSources("example.properties")
public interface ExampleConfig extends KrauseningConfig {
@Key("fibonacci")
List<Integer> getFibonacciSeq();
@Key("fullUrl")
URL getFullUrl();
@Key("pi")
double getPi();
@Key("not-defined-in-prop-file")
@DefaultValue("1234")
int getInt();
}
```
2. Access properties via the newly created interface:
```java
ExampleConfig config = KrauseningConfigFactory.create(ExampleConfig.class);
assertEquals(3, config.getFibonacciSeq().get(3));
assertEquals(new URL("https://prodUrl/foo/baz/endpoint"), config.getFullUrl());
assertEquals(3.1415d, config.getPi());
assertEquals(1234, config.getInt());
```
3. Optionally, get a list of all the properties in the newly created interface by calling the configuration fill() method:
```java
ExampleConfig config = KrauseningConfigFactory.create(ExampleConfig.class);
Properties properties = new Properties();
config.fill(properties);
assertTrue(properties.keySet().contains("pi"));
assertEquals("3.1415",properties.getProperty("pi"));
```
4. Check out `KrauseningConfigTest` in `src/test/java` and/or the Owner documentation for additional information on how to best utilize the Krausening-Owner integration.
# Last Call
You're now 5 pints in and ready for how ever many more property files you need without having to worry about stumbling through deployment!

# Krausening and Python

See the [krausening-python README](https://bitbucket.org/cpointe/krausening/src/dev/krausening-python/) for more details.
See the [krausening-python README](https://github.com/TechnologyBrewery/krausening/tree/dev/krausening-python/) for more details.

# Contributions
See the CONTRIBUTING.md file in the Krausening root directory for release instructions and general architecture information.

# Distribution Channel

Want Krausening in your project? The following Maven dependency will add the Java implementation of Krausening to your Maven project from the Maven Central Repository:

```xml
<dependency>
<groupId>org.technologybrewery.krausening</groupId>
<artifactId>krausening</artifactId>
<version>16</version>
</dependency>
```


## Licensing
Krausening is available under the [MIT License](http://opensource.org/licenses/mit-license.php).

## Session Beer
Krausening would like to thank [Counterpointe Solutions](http://cpointe-inc.com/) for providing continuous integration and static code analysis services for Krausening.
See the CONTRIBUTING.md file in the Krausening root directory for release instructions.
20 changes: 8 additions & 12 deletions krausening-python/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# Krausening Python - Externalized Property Management and Access for Python Projects #
[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/mit)
[![PyPI](https://img.shields.io/pypi/v/krausening)](https://pypi.org/project/krausening/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/krausening)
![PyPI - Wheel](https://img.shields.io/pypi/wheel/krausening)
[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/mit)

Krausening property management and encryption for Python is packaged using the open-source Python Maven plugin [Habushu](https://bitbucket.org/cpointe/habushu) and made available as a [PyPI package](https://pypi.org/project/krausening/).

Krausening property management and encryption for Python is packaged using the open-source Python Maven plugin [Habushu](https://bitbucket.org/cpointe/habushu) and made available as a [PyPI package](https://pypi.org/project/krausening/).
## Distribution Channel

Krausening Python is published to PyPI under the [krausening](https://pypi.org/project/krausening/) project and may be installed using any package installer/manager that leverages PyPI. For example:

* [Poetry](https://python-poetry.org/) - `poetry add krausening`
* [pip](https://pip.pypa.io/) - `pip install krausening`

## Managing Properties with Krausening and Python

Expand Down Expand Up @@ -54,16 +60,6 @@ class TestConfig():
def reload(self):
self.properties = PropertyManager.get_instance().get_properties('test.properties')
```

**Note: Due to updates the M1 Apple Chip, we strongly recommend using Python >= 3.9 for compatibility reasons.**

## Distribution Channel

Krausening Python is published to PyPI under the [krausening](https://pypi.org/project/krausening/) project and may be installed using any package installer/manager that leverages PyPI. For example:

* [Poetry](https://python-poetry.org/) - `poetry add krausening`
* [pip](https://pip.pypa.io/) - `pip install krausening`

## Releasing to PyPI

Releasing Krausening Python integrates into the project's larger utilization of the `maven-release-plugin`, specifically publishing the package to PyPI during the `deploy` phase. A [PyPI account](https://pypi.org/account/register/) with access to the [krausening](https://pypi.org/project/krausening/) project is required. PyPI account credentials should be specified in your `settings.xml` under the `<id>pypi</id>` `<server>` entry:
Expand Down
4 changes: 2 additions & 2 deletions krausening-python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
name = "krausening"
version = "16.dev"
description = "Python implementation of Krausening"
authors = ["Eric Konieczny <ekonieczny@cpointe-inc.com>"]
authors = ["Eric Konieczny <ekoniec1@gmail.com>"]
license = "MIT"
readme = "README.md"
repository = "https://bitbucket.org/cpointe/krausening"
repository = "https://github.com/TechnologyBrewery/krausening"

keywords = ["properties", "configuration-management"]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PropertyEncryptor:
Reference: https://resultfor.dev/359470-implement-pbewithhmacsha512andaes-256-of-java-jasypt-in-python.
See https://bitbucket.org/cpointe/krausening/src/dev/ for details on encrypting values with Jasypt.
See https://github.com/TechnologyBrewery/krausening/tree/dev/krausening for details on encrypting values with Jasypt.
"""

def encrypt(self, value_to_encrypt: str, password: bytes) -> bytes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class EncryptableProperties(Properties):
Reference: https://resultfor.dev/359470-implement-pbewithhmacsha512andaes-256-of-java-jasypt-in-python.
See https://bitbucket.org/cpointe/krausening/src/dev/ for details on encrypting values with Jasypt.
See https:https://github.com/TechnologyBrewery/krausening/tree/dev/krausening for details on encrypting values with Jasypt.
"""

def __init__(self, password: str) -> None:
Expand Down
Loading

0 comments on commit c1d37ef

Please sign in to comment.