[wildfly-dev] Capabilit integration from services and DeploymentUnitProcessors

Brian Stansberry brian.stansberry at redhat.com
Tue Jun 30 14:30:12 EDT 2015


tl;dr; DUPs may need access to the integration APIs provided by 
capabilities. I've got a first cut solution to that, but there are edge 
cases that don't work well and we may need to restrict how capabilities 
work a bit.

Long version.

WildFly Core capabilities are meant to provide a standardized way for 
parts of the server to integrate with each other.[1]

Use of these is proceeding pretty nicely in the OperationStepHandlers 
the kernel and subsystems use for executing management operations. But 
in some cases, the code that needs to integrate with a capability isn't 
in an OSH. It can be in a service start method, particularly in a 
DeploymentUnitProcessor. (DUPs run in a service start method.)

A simple example would be a deployment descriptor or annotation includes 
a chunk of config that specifies the use of a subsystem-provided 
resource, say a cache. The DUP then wants to figure out the service name 
of that resource, using capabilities.

So I've started to give some thought to how to handle that. See 
https://github.com/bstansberry/wildfly-core/commit/ba7321bc30374b2d0aa99cbf344d50b50fa2eea6 
for a first cut.

Basically the OperationContext exposes a "CapabilityServiceSupport" 
object that OSHs can provide to services they install. The services can 
then use that to look up service names and any custom runtime API 
provided by a capability.

Typical pattern would be the OSH for a "deploy" op would make the 
CapabilityServiceSupport available to RootDeploymentUnitService, which 
would expose it to DUPs via a DeploymentPhaseContext attachment. DUPs, 
as they install services would use the CapabilityServiceSupport to look 
up service names and add dependencies to that new service.

The service doesn't register any requirement for the capability. If it 
tries to use a non-existent capability, an exception is thrown and the 
service has to deal with it. *This is the main problem.* The caller is 
unable to register a dependency (since it can't get the service name) so 
the MSC behavior of letting the service be installed but fail to start 
due to a missing dependency is short circuited.

In most cases, if a service is installed but fails to start due to a 
missing dependency, the management op that installed it is rolled back, 
so the end result is the same. But we do support the 
"rollback-on-runtime-failure=false" management op header, and if that's 
used our behavior would be changed for the worse.

A possible partial solution to this would be to tighten down the rules 
for how service names are created from capability names. Basically, any 
capability could only provide 1 service, and the name of the service 
would be the result of passing the name of the capability to 
ServiceName.parse(name). That's the default behavior now, but we support 
other options.

That would fix the service name discovery problem, by making the name 
discovery algorithm completely static. It wouldn't help with a case 
where a DUP needs access to a custom runtime API exposed by a 
capability. But that is much more of a corner case. Probably better to 
discuss on a sub branch of this thread. :)

What would we lose if we tightened down the service name rules?

1) Capabilities would not be able to tell the service name discovery 
logic to produce some legacy service naming pattern (i.e. keep service 
names as they were in earlier releases.)

This one I don't think is a big deal, as the capability can always 
register an alias for the service that uses the legacy service name.

2) A capability cannot provide services of > 1 value type. It's nice if 
capabilities can represent something that's meaningful to an end user, 
and there's no reason why something that's meaningful to an end user 
might not expose more than one service to other capabilities. If we 
limit capabilities to exposing a single service, then we may end up with 
multiple capabilities. See [2] for an example case, where a proposed 
"org.wildfly.iiop" (nice and simple for an end user to understand) 
installs two services, an ORB and a NamingContextExt.

At this point though, capability names aren't really exposed to end 
users, so perhaps we can put this problem aside for now. If it becomes 
an issue later, there are solutions, e.g. a user-friendly 
"org.wildfly.iiop" capability automatically registers the detailed 
"org.wildfly.iiop.orb" and "org.wildfly.iiop.naming" capabilities, 
helping the user ignore the details.

Sorry for the long tome; by now I expect folks are used to it!

[1] Specifically, to validate that references to other parts of the 
configuration are valid, to determine the names of MSC services provided 
by other parts of the system, and to access any custom runtime 
integration API exposed by another part of the system.

[2] 
https://github.com/bstansberry/wildfly/commit/b9de64e046404531df466288cf4fb1f99b917636#diff-04ae38c6384a018059f5411e261f0d61R86

-- 
Brian Stansberry
Senior Principal Software Engineer
JBoss by Red Hat


More information about the wildfly-dev mailing list