Questions Applicable to All Scenarios Above
- What is the application assembler supposed to do in general here?
- How does she know what configuration properties are being requested by the Jakarta EE components?
- How does she know that each component is expecting a different sort of thing or behavior under the same name?
- How does she know what Converters are in the picture? Can she somehow override them? (Remember, in case it matters, that the application assembler as defined in the Platform Specification doesn't write or compile code.)
- How does she reconcile all this? That is, how does she, or someone playing the configuration author role, write appropriate configuration for each scenario that satisfies each component?
- What if component-supplied Converters have priorities of Integer.MAX_VALUE? (How would she know?)
In order to try and address these questions, I'll coerce them into draft use cases/user stories. Note that the following are drafts; I'm not endorsing any particular use case (yet) unless stated specifically within each use case. This is mainly a way to try and capture the ideas presented above in this format.
As a component developer, I must be able to specify which configuration properties are required and which are optional, along with their types, so that the configuration may be validated.
This is the foundational capability which enables all of these requirements. Without this type of validation, it is not possible to know what properties are being requested, and which are required.
In terms of converters, the way I see it, the specification of the configuration property's type (and thus the converter) must only be the purview of the component developer. Giving the assembler or the deployer control over this aspect is not the appropriate resolution to any use case IMO, including but not limited to the case where multiple components request properties of the same name but with different types or semantic meanings.
There is a complexity here in that we may differentiate between configuration that is acquired programmatically versus configuration that is (for example) mapped to an object model of some sort. In the latter case, the tool which does the mapping generally has all of the information/metadata it needs to create a comprehensive manifest of configuration properties. However, in the former (programmatic) case, no such metadata exists; in order to meet this requirement, the component developer would be required to provide this information separately somehow.
As an application assembler, I must be able to know which configuration properties are expected by each component so that I can ensure that all of the necessary configuration can be provided.
As Laird noted, the assembler may not be able or willing to examine the source code of the component (it is not part of their role). Thus, if this is a valid use case, there would need to be some kind of tooling or automated means for the assembler to examine the total set of properties that are required by an application which is available *before* deployment.
I'm not sure that I agree with this use case. It is arguably useful, but it might not be practical to implement.
As an application deployer, I must know that the configuration of the component is valid before deployment completes, in order to prevent the application from starting with an incorrect or inconsistent configuration, or even worse, a security vulnerability.
This would amount to some sort of deployment-time validation. The metadata encoded by the implementation of Story 1 would be used to examine the configuration to establish some or all of the following:
- Whether the configuration is missing any required properties
- Whether the configuration contains properties which are unrecognized or unexpected
- Whether the value of each given configuration property is valid in terms of its type
- Whether the value of each given configuration property is valid in terms of any particular imposed validation constraints
Note that point #2 above is very useful but also particularly tricky. Within Quarkus we establish the complete set of recognized properties within a particular namespace (e.g. "quarkus.**"), and produce an error if an unknown property is given. This works well as long as it is confined to a namespace, but not so well (with MP Config) otherwise, since it is common for MP configuration sources to include properties that are unrelated to the actual configuration (mainly due to system property and environment variable config sources).
As an application assembler, I must have a means to resolve namespace conflicts between components, so that I can package components that are not aware of each others' namespace usage.
It is proposed above that it is feasible that two components may consume properties with the same name but with different types and/or semantics. Presumably, without a means to resolve such an ambiguity, the burden would fall on the component developers to be aware of one another and to coordinate property names and namespaces among themselves - something which may or may not be feasible.
Nevertheless I am not sure I agree with this use case. On the one hand, it may be possible to resolve the problem by (for example) providing the application assembler with a means to namespace each component, or to somehow provide distinct configurations on a per-component basis. I don't think that this is the right solution to the problem though; both would add a burden of complexity to the assembly job while not really addressing the fundamental cause of the problem - rather working around it.
It is my opinion that the MP Config solution of globally namespacing each configuration key is *probably* adequate for the majority of situations. A properly namespaced configuration key conveys not only ownership but indirectly the type and semantic behavior of the property as well, in the form of documentation if nothing else. A key of "name" is hopelessly ambiguous, but a key of "org.mycompany.storefront.name
" is very specific and clear. The question would be whether it is likely (for example) that there would be two of the same component packaged in an application; that would be where this assertion falls apart I suspect.
In particular, I do not think that it would be correct for the assembler to somehow adjust the converter behavior in order to resolve this kind of conflict.
Laird, do these use cases adequately capture all of the ideas you are trying to convey? Is something missing or misrepresented?