[wildfly-dev] Capabilit integration from services and DeploymentUnitProcessors

James R. Perkins jperkins at redhat.com
Tue Jun 30 17:44:41 EDT 2015



On 06/30/2015 11:30 AM, Brian Stansberry wrote:
> 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.
Data sources are another good example. A data source can be defined in 
the datasource subsystem, in a deployment with an *-ds.xml descriptor or 
a couple standard Java EE ways. I've opened a PR [1] to expose the 
subsystem resource as a capability. I registered the legacy service name 
as an alias to the capabilities resolved service name. I don't however 
use the capability service name for the services added via the DUP's. 
One reason being the support wasn't there for it, though it could be 
done with some simple helpers. The second reason is some what of a 
tangent and off topic, but I'll go ahead with it :)

For data source resources a dynamic RuntimeCapability is used. The 
dynamic name for the capability is the name of resource, e.g. ExampleDS 
for the default configuration. This is useful for things like the batch 
subsystem that may need a data source but don't want to rely on a JNDI 
name as it's messy. However deployments that define their own data 
source, say via @DataSourceDefinition annotation, don't have a resource 
so the name used for the service is the JNDI name. While that's 
irrelevant to a subsystem that wants the capability it is relevant to a 
say a JPA deployment that needs to know which data source to use based 
on the JNDI name. That requires that a service always have an alias to 
match the DUP dependency service name for the data source to avoid 
duplicate entries.

After re-reading the above I'm not sure what I'm on about and it seems 
very off topic for this subject. I'm leaving it however as just 
something for others to think about when add capabilities.

[1]: https://github.com/wildfly/wildfly/pull/7682
>
> 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.
If it's somewhat considered a capability maybe short-circuiting the MSC 
behavior is okay. I suppose in cases where that could be an issue an 
alias could be used and then a standard ServiceName dependency added to 
the DUP service.
>
> 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.
Having more than one service tied to a capability is something I didn't 
think of. I like the idea of a 1-1 relationship between a service and a 
capability, but it does make sense what's happening here for IIOP.

I guess one idea might be to provide some kind of parent/child 
relationship. Maybe not a deep hierarchy but something where I could say 
as a consumer give me "org.wildfly.iiop" and I'd get "orb" and "naming" 
capabilities. Or just say give me the "org.wildfly.iiop.orb" only 
capability. Though this will probably really complicate things.
>
> 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
>

-- 
James R. Perkins
JBoss by Red Hat



More information about the wildfly-dev mailing list