This is a high-level task meant to serve as the parent for subsystem-specific subtasks. Actual changes to subsystems should be tracked via those subtasks.
The general point here is to try and eliminate multiple disparate variants of subsystem code so people maintaining code can quickly understand any subsystem and so people creating new subsystems can safely look at any existing subsystem as a reasonable pattern to follow. Eliminating different code variants should also reduce the memory footprint of the server.
Subsystems should be written based on the management API classes in the wildly-controller module or, for subsystems in main Wildfly, the ‘clustering’ subsystem development APIs. (I think this is already generally the case, although there may be bits and pieces of custom handlers that duplicate wildly-controller.)
Moving from the wildly-controller APIs to the clustering ones, or vice-versa, should be avoided when working on this task. This is just a matter of scope limitation as such a move is expensive to review and we have other priorities.
1) Extension impls should not be constructing the ResourceDefinition tree. They should set up the root nodes, and then the ResourceDefinitions configure themselves and add their children. (An exception to this could be extensions that seek to reduce memory utilization by constructing the ResourceDefinition tree from the children working back to the root. Before any extension does that we should have a discussion of the best idioms for that so we don't end up with multiple varieties. But the existing cases I'm aware of of extensions constructing the tree in the Extension impl are not of this type; they are starting from the tree root and working to the leaves.)
2) Custom implementations of functionality available from standard APIs should be replaced by use of the standard APIs. In particular:
- OperationContext.getCurrentAddress should be used in place of reading the address from the operation ModelNode
- OperationContext.getCurrentAddressValue should be used instead of manipulating the operation ModelNode or a PathAddress derived from it.
- ModelNode.asXXXOrNull should be used in place of custom code that does the same thing. There is a lot of this kind of code as most subsystems were written before asXXXOrNull was available.
3) AttributeDefinition.resolveModelReference should be used when obtaining values passed to runtime services. (We already evaluated code for this, but double checking doesn’t hurt.)
4) ResourceDefinitions that register write attribute handlers by looping through the attributes and instantiating an instance of the same handler class for each should aim to construct one handler instance outside the loop.
5) Attributes that reference other resources must be backed by a capability and a credential reference.
6) Stage.RUNTIME handlers that add dependencies on services from other subsystems should use the capability APIs for service wiring.
7) Use of ModelNode.resolve in production subsystem code should be eliminated. In places where this is difficult (e.g. in xml parsers) we should discuss workarounds.
8) Use of ModelNode.asXXX(defaultXXX), e.g. node.asBoolean(false) should replaced by plain asXXX() or asXXXorNull() in the typical cases where the node was obtained from a call to AttributeDefinition.resolveModelAttribute. The defaultXXX value should be specified as the default value of the AttributeDefinition. If that is done, the asXXX(defaultXXX) call is redundant.
9) SimpleResourceDefinition subclasses should pass a Parameters object to the superclass constructor.
10) Service wiring should move to the MSC 2 APIs. There may be cases where this may be problematic; if so those should be discussed.
Following any changes, read-resource-description output from the unchanged API should be compared to the changed API to confirm there are no unwanted changes. If changes are detected that are considered to be correct, a separate issue should be filed. Subsystem API version bumps should be done when appropriate.