Support a proper whenElementKnown hook. The internal container hook of the same name in vanilla container APIs is quite broken. For this reason, we need to establish three distinct hooks to catch all possible entries from both vanilla and universal model and properly execute a whenElementKnown hook.
Support vanilla Gradle API together with the universal model. We need to make the best effort so the vanilla container APIs and universal model APIs behave very similarly. According to our experimentation, eagerly created elements will be a big issue and we won't be able to safely use them. The configuration action ordering becomes very messy, very quickly.
Support discovery/realization hooks. In the universal model, we can catch the realization of the domain object and perform the adequate steps for a successful, ordered, realization. In the vanilla container, we can only catch the realization once the creating provider is executing which we then need to execute additional steps. During those steps, we can cause further configuration of the domain object which, unfortunately, will be out-of-order without a creative solution. The main reason for a creative solution boils down to this line.
The first hook from number 1 is whenElementKnown which works only if the element is registered via register API. Note that the whenElementKnown action is executed twice (once on the register and once on the element realization). On a create API call, the whenElementKnown action is executed once after all configureEach actions. The second hook is very early (if possible the first configuration) configureEach to catch any create API call (as mentioned before, in this scenario, the actions are called too late). The final hook is in our register API which will properly detect when an element is known. An additional hook can be used if we use standardized NamedDomainObjectFactory (only for ad-hoc ExtensiblePolymorphicDomainObjectContainer or NamedDomainObjectContainer) which is a better replacement to the first hook and avoid issue noted in point number 3.
For discovery/realization hooks (point number 3), out-of-order configuration is an issue.We can avoid the issue if users uses our generated NamedDomainObjectProvider/TaskProvider which we can intercept the configure API and bounce the configuration via the whenElementKnown configuration delaying the configuration to the end. Another clever alternative is to disalign configuration action but that would execute configuration action in a strange way that may lead to hard to debug code as well as create a disconnect between configuration action registered via vanilla model vs universal model. The following snippet shows how to bounce the action via whenElementKnown:
The expected ordering is a1, a2, a4 then a3. Note that a3 would normally be nested configuration only discoverable once the parent domain objects are realized. There is still an issue with ordering in a case like the following:
Assuming the library closure is deferred then action 1 and 3 would execute before action 2 as action 2 would only be known once library is realized. The solution here is outside of the scope of this issue but would involve reordering the action based on some global counter for configuration action. we could see that library closure would be noted as 2 which would lead the nested action noted as 2.1 (the first action under action 2 from the parent layer. The configureEach action would then be 1, 3, and 2.1. By reordering the actions before execution, we would correctly have 1, 2.1, and 3. We can see that such accuracy under these scenario is only achievable if and only if we have fully visibility on the configuration actions as well as all domain object are lazily registered, thus disallowing create APIs.
Not that we count 3 callbacks to whenElementKnown, once when we add the hook and 2 more times as part of the normal workflow of that API when registered.
There are three things that we need to support:
whenElementKnown
hook. The internal container hook of the same name in vanilla container APIs is quite broken. For this reason, we need to establish three distinct hooks to catch all possible entries from both vanilla and universal model and properly execute awhenElementKnown
hook.The first hook from number 1 is
whenElementKnown
which works only if the element is registered viaregister
API. Note that thewhenElementKnown
action is executed twice (once on the register and once on the element realization). On acreate
API call, thewhenElementKnown
action is executed once after allconfigureEach
actions. The second hook is very early (if possible the first configuration)configureEach
to catch anycreate
API call (as mentioned before, in this scenario, the actions are called too late). The final hook is in ourregister
API which will properly detect when an element is known. An additional hook can be used if we use standardizedNamedDomainObjectFactory
(only for ad-hocExtensiblePolymorphicDomainObjectContainer
orNamedDomainObjectContainer
) which is a better replacement to the first hook and avoid issue noted in point number 3.For discovery/realization hooks (point number 3), out-of-order configuration is an issue.We can avoid the issue if users uses our generated
NamedDomainObjectProvider
/TaskProvider
which we can intercept theconfigure
API and bounce the configuration via thewhenElementKnown
configuration delaying the configuration to the end. Another clever alternative is to disalign configuration action but that would execute configuration action in a strange way that may lead to hard to debug code as well as create a disconnect between configuration action registered via vanilla model vs universal model. The following snippet shows how to bounce the action viawhenElementKnown
:The expected ordering is
a1
,a2
,a4
thena3
. Note thata3
would normally be nested configuration only discoverable once the parent domain objects are realized. There is still an issue with ordering in a case like the following:Assuming the
library
closure is deferred then action 1 and 3 would execute before action 2 as action 2 would only be known oncelibrary
is realized. The solution here is outside of the scope of this issue but would involve reordering the action based on some global counter for configuration action. we could see thatlibrary
closure would be noted as2
which would lead the nested action noted as2.1
(the first action under action 2 from the parent layer. The configureEach action would then be1
,3
, and2.1
. By reordering the actions before execution, we would correctly have1
,2.1
, and3
. We can see that such accuracy under these scenario is only achievable if and only if we have fully visibility on the configuration actions as well as all domain object are lazily registered, thus disallowingcreate
APIs.