Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1001 Application-level profile and property management #1109

Merged
merged 22 commits into from
Dec 24, 2024

Conversation

GuusLieben
Copy link
Member

@GuusLieben GuusLieben commented Jul 31, 2024

Type of Change

  • Feature (non-breaking change that adds functionality)

Description

The current system lacks a straightforward method for managing distinct profiles within the same application, such as development and production profiles.

These changes introduce two new modules: hartshorn-properties and hartshorn-profiles. The properties module is integrated in hartshorn-inject, hartshorn-inject-configurations, and hartshorn-launchpad. The profiles module is only integrated in hartshorn-launchpad.

Hartshorn Properties

Properties form an important part of Hartshorn applications. Even more so, they play an important role early in the application bootstrapping process. As such, properties should be loaded early on, without the need for additional application components to be present.

Properties are loaded in three phases:

  • A PropertyRegistryLoader reads configuration sources, defining ConfiguredProperty instances for each configured property
  • A PropertyRegistry receives configured properties from the loader, and stores them in an accessible manner
  • Callers can obtain structured configuration objects, lists, and values from the PropertyRegistry
About registry loaders

The default implementations of the PropertyRegistryLoader use Jackson object mapping in the background, transforming configuration into trees, which are formatted into individual property paths in the shape of ConfiguredProperty instances before proceeding to a property registry. Support for YAML and JavaProps is present by default, though additional implementations can be added with relative ease (including other Jackson mapper implementations, if preferred).

Note that current loaders are designed for external properties, coming from generic Path definitions. System- and environment variables are currently not integrated, but will be followed up in #1121.

About configured properties

Configured properties are intermediate property entries. Their main purpose is to allow for the easy identification of properties within a property registry. Configured properties themselves are nothing more than key-value pairs, where the key is the fully qualified name of the property.

For example, for the YAML sample below, the sole ConfiguredProperty instance would be sample.list[0].value = xyz.

sample:
  list:
    - value: 'xyz'
About property registries and properties

The standard PropertyRegistry implementation is the MapPropertyRegistry which, as the name suggests, stores properties in a local map for easy lookup. While registries store 'configured properties', they rarely expose properties in that form. Instead, properties can be exposed in one of three ways:

  • As a ListProperty, which is a list of other properties of any of the three main representations
  • As a ObjectProperty, which is a map of key-property entries where each property is one of any of the three main representations
  • As a ValueProperty, which is a single value property. Values are saved as string values, and can be parsed either manually of through the use of a ValuePropertyParser
About property parsing

As properties are only stored as plain string values, they are rarely in the exact shape callers need them (e.g. as a number, enum, or complex types). To support the base scenarios, StandardValuePropertyParsers implements various parsers for primitive types, and EnumValuePropertyParser implements enum support.

Additional parsers can be added easily by either implementing ValuePropertyParser directly, or by using either GenericConverterValuePropertyParser or ConverterValuePropertyParser with a pre-existing GenericConverter or Converter implementation (most primitive parsers use these implementations as well, so you can expect the same behavior for converters and parsers).

Property value injection

In most cases you won't need the full flexibility of the property registries, as you'll only want to resolve a single value. While you can achieve this with PropertyRegistry.value("property.path", SomeConverterValuePropertyParser), this is likely a bit overkill, and not the easiest to figure out if you haven't used it before.

As such, it's also possible to directly inject property values into your components (or any other supported injection point). Simply annotate your injection point (field or parameter) with @PropertyValue and provide a name and optional default value. The default value is only used if there is no property with the given name.

There are four permitted scenarios for property value injection:

  • The target type is ValueProperty (1), ListProperty (2), or ObjectProperty (3), in which case the property is directly obtained from the registry
  • The target type is any other type than those mentioned above, in which case a ValueProperty is resolved from the property registry, and passed to the ConversionService. All pre-existing string-to-xyz converters are supported. Additional converters which convert either ValueProperty or String to a target type are also supported.

Hartshorn Profiles

The profiles module builds on top of the properties module, adding the ability to separate configurations for different scenarios (such as different environments or deployment goals). Profiles are loaded based on the value of the hartshorn.profiles property, which is read from the 'root' property registry. The root registry is the first registry to be loaded, typically from application.yml | .properties files.

This module is relatively small, and only adds a utility layer to easily work with multiple profiles in a hierarchical manner. In Launchpad this is integrated more deeply to bootstrap the configurations when the application starts.

Checklist

  • I have performed a self-review of my own code
  • I have added tests that prove it is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Related issue number is linked in pull request title
  • I have added documentation that describes my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have rebased my branch on top of the latest develop branch

Related Issue

Closes #1001

@GuusLieben GuusLieben self-assigned this Jul 31, 2024
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from 343dabf to 17f38c1 Compare July 31, 2024 18:14
@GuusLieben GuusLieben modified the milestones: 0.6.0, 0.7.0 Jul 31, 2024
@GuusLieben GuusLieben force-pushed the feature/#1092-module-migration branch from 5529e1e to ffccdf8 Compare August 2, 2024 07:32
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from 17f38c1 to 549c169 Compare August 2, 2024 07:34
Base automatically changed from feature/#1092-module-migration to develop/0.7.0 August 11, 2024 11:35
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from 549c169 to e1dc83b Compare December 21, 2024 17:06
# Conflicts:
#	hartshorn-launchpad/src/main/java/org/dockbox/hartshorn/launchpad/environment/BuildEnvironmentPredicate.java
#	hartshorn-launchpad/src/test/java/test/org/dockbox/hartshorn/testsuite/ModifyApplicationTests.java
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from e1dc83b to aec4c02 Compare December 21, 2024 18:10
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from 0bdbce9 to b5e1d81 Compare December 22, 2024 16:05
@GuusLieben GuusLieben force-pushed the feature/#1001-property-management branch from 1a03511 to 2962126 Compare December 23, 2024 16:00
@GuusLieben GuusLieben marked this pull request as ready for review December 24, 2024 15:00
@GuusLieben GuusLieben merged commit 836bb99 into develop/0.7.0 Dec 24, 2024
9 checks passed
@GuusLieben GuusLieben deleted the feature/#1001-property-management branch December 24, 2024 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Application-level profile and property management
1 participant