See: Description
Package | Description |
---|---|
org.microbean.settings | |
org.microbean.settings.converter |
Provides classes and interfaces that help with settings
conversion.
|
Provides classes and interfaces that help with acquiring settings from CDI-based programs.
The microBean™ Settings framework serves as a single locus from which a CDI-based Java program may read settings: deployment-time information and configuration often packaged externally with respect to the program that tailors that program to its runtime environment.
A setting is a non-specific conceptual entity that loosely and imprecisely describes an aspect of something that can be externally configured.
The term setting as commonly used is slippery and
ambiguous. Sometimes people use "setting" to mean
the name of a property or
attribute that can be externally configured in some way ("the
setting that controls debug information", "what's the debug
setting set to?"). Other times people use "setting" to
mean a particular
value of something that can
be externally configured ("what's the setting for the debug
property?"). Still other times people use "setting" to
mean an environmentally specific particular
value of something that can be configured ("use the staging
setting for debug
").
Due in part to this ambiguity, this project deliberately does not represent a setting in Java code. Instead, this project carefully distinguishes between setting names, setting values, and qualifiers.
A setting name is fundamentally a String
. It is not hierarchical. It is treated as a
unique key that, together with
qualifiers, which will be
discussed later, can pick out a
maximally suitable setting
value from among many
possible suitable setting
values.
For example, the setting name for a hypothetical debug
setting should be, simply, debug
,
even if there could be many potentially
suitable setting values for this
setting name. Potentially suitable
(and potentially incompatible) setting
values might include:
debug
setting name in the production
environment, all else
being equaldevelopment
environment, all else being equaleast
data center region, all else being equaleast
data center region
but regardless of environment…and so on.
To belabor the point, and most notably in this example, the
setting name would not be anything like production.debug
, or development.debug
or east.debug
, because setting names are not hierarchical. It would
be, simply, debug
. The mechanism to distinguish between
these hypothetical setting values in
the absence of hierarchical setting
names, qualifiers, will be
discussed below.
A setting value is, fundamentally, deliberately and canonically a textual value, since that is the form in which most setting values are stored, and also particularly since, being configuration information, setting values are designed to be human-editable.
Setting values conceptually are always paired with the setting name they are associated with. Bear in mind, however, that several potential setting values may be associated with any given setting name. Some of them may be more or less suitable for one particular application but not for another. Suitability is covered later below.
A setting value conceptually
originates from a source, which is simply and somewhat
circularly any furnisher of (definitionally
textual) setting values. Sources are
represented in Java code in this project by instances of the
Source
class.
In this project, a Source
is the
atomic unit of setting value
acquisition and serves as a façade on top of systems
ranging from simple text files to entire configuration subsystems.
Colloquially speaking, you can ask a Source
for a
Value
that
is suitable for a
setting named by a
particular setting name, and it will
respond with zero or one of them.
Setting value acquisition is the process of acquiring a setting value given a setting name and some information about the settings space in which the setting value acquisition is taking place.
This settings space information is more precisely known as qualifiers.
A qualifier is a conceptual pairing of a named environmental aspect and its value that, together, pick out a single coordinate in an overall settings space.
Consider a hypothetical, deliberately simplified organization that
deploys many programs across east
and west
data
center region
s, and places them into development
,
staging
and production
environment
s, and
conducts named featureTest
s across them. A program
running in this world has coordinates—qualifiers—in
this settings space. Specifically, a program's settings space
qualifiers distinguish it in this hypothetical world
by qualifying its location in settings space: along the
environment
axis (environment=development
, or
environment=staging
, or environment=production
),
its location along the region
axis (region=east
or
region=west
), and its location along the featureTest
axis (featureTest=blinkTag
or featureTest=autoplay
or a potentially infinite number of other
possibilities).
It is extremely important to understand that qualifiers,
like setting names, are not inherently hierarchichal.
For example, given two setting
values, one qualified with environment=development
and
region=east
, and another qualified with environment=development
and featureTest=blinkTag
, which
is "best" for an application in the development
environment, running in the east
region and undergoing the
blinkTag
feature test? It is not immediately clear, and
this is why setting names and
qualifiers are not expressed in terms of a hierarchical namespace.
A qualifier is represented in Java code in this project by
instances of the Annotation
class,
following a similar concept
in CDI.
A setting value request is the logical sending of a pair of a setting name and some qualifiers to one or more sources.
A well-behaved source that is provided with this information will either furnish exactly one setting value response for the conceptual setting identified by the setting value request, or will indicate that it can furnish no suitable setting value response.
If a source furnishes a setting value response, then the setting value response is said to be suitable to some degree.
A setting value response is the logical sending of a logical tuple consisting of a setting name, a suitable setting value, and a subset of the setting value request's qualifiers from which a degree of suitability is derived in response to the reception of a setting value request.
A setting value response's suitability for its corresponding setting value request is a measure of how suited—how tailored, how specific—its associated setting value is for a given setting value request.
Setting value response suitability is represented by the fact that a setting value response has qualifiers, in a manner similar to how a setting value request has qualifiers. To be at all suitable, a setting value response's qualifiers must be either equal in kind and number to the set of qualifiers present in the corresponding setting value request, or a subset in kind and number of those qualifiers.
Therefore, a setting value response whose qualifiers are smaller in number than the qualifiers in its corresponding value acquisition request is less suitable for the setting in question than a setting value whose qualifiers are equal in number to the qualifiers in its corresponding setting value request.
Colloquially speaking, in other words: if
a setting value request for a
setting named debug
arrives at
a source with
qualifiers {environment=production,
region=east}
, then
a setting value response
whose qualifiers are
{environment=production}
is less suitable for that
setting value request than a setting value response whose
qualifiers are {environment=production, region=east}
,
and a setting value response whose qualifiers are empty is the
least suitable of all possible setting values for that value
acquisition request.
When each of two sources responds to a setting value request, a requester must choose between the two setting value responses received. Sometimes, choosing is easy: if there is only one suitable setting value response, then there is no question that its associated setting value is the one that should be used, or if there is one setting value response that is more suitable than another, then obviously the more suitable one should be chosen. But if two setting value requests are equally suitable, some other mechanism to disambiguate them must be used. This is called value arbitration.
Value arbitration is carried out by an arbiter. An
arbiter is a notional resolver of otherwise ambiguous setting
value responses. It receives two or more setting value responses
with equal suitability and uses whatever heuristic it likes to
choose between them. Arbiters are represented in Java code in
this project by instances of the Arbiter
class.
If an arbiter cannot arbitrate multiple ambiguous setting value responses, then the overall process of setting value acquisition fails.
A setting value may contain references to other setting names for which setting value requests should be issued. Processing these references is known as interpolation.
All interpolation in this project is carried out by an implementation of the Jakarta Expression Language.
For example, in this project, for
a setting name of, say, javaHomeDescription
, a
potentially suitable setting
value of "Your java.home variable is:
${settings['java.home']}
" will be interpreted such that
during setting value
acquisition a setting value
request will be issued for a
setting named java.home
, and
any value received for that setting name will replace
"${settings['java.home']}
".
Once a setting value has been
successfully acquired, it
might need to be converted into a different data type. For
example, a setting value of "1
"—a String
—might be better
represented within Java code as an Integer
. Conversion is the process of
transforming a (definitionally) textual-typed setting value (such
as a String
) into another data type
representation (such as an Integer
).
A converter is a notional, preferably stateless entity
that can accept a (definitionally
textual) setting value and, without
changing its meaning, represent it using a particular programming
language data type. Converters are represented in Java code in
this project by implementations of the Converter
interface.
In this project, the Settings
class
encapsulates all aspects
of setting value
acquisition described above. A Settings
instance gathers together Source
s, Arbiter
s, Converter
s and a pluggable implementation
of
the Jakarta
Expression Language to provide setting value acquisition
services via methods like Settings.get(String, Set,
Converter, BiFunction)
.
Copyright © 2019–2020, microBean™. All rights reserved.