Package com.xebialabs.xlrelease.osgi.spring
package com.xebialabs.xlrelease.osgi.spring
-
ClassDescriptionThrown by
PluginManifest.from(Bundle)when a bundle declares itself a Spring plugin (it has anX-Plugin-Contextheader) but its manifest is malformed.Discovers Spring plugin bundles via thePluginManifestcontract, builds their child context viaPluginContextFactory, and guarantees deterministic teardown onremovedBundle- including plainbundle.stop()with no uninstall, the gap aServiceTracker-only approach cannot close (see.opencode/tech/osgi.md:58-62:removedBundlefires synchronously, on the calling thread, with a fully usable bundle classloader, for uninstall, stop-alone, and framework shutdown alike).Purges the enumerable set of JDK/Spring caches that would otherwise pin a departing plugin's classloader - a hand-rolled list, after rejectingClassLoaderLeakPreventor(stale since 2016, and its API assumes aServletContextEventrather than an arbitraryClassLoader).A production safety net, independent of the CI-only leak-gate test suite: afterPluginTeardown.teardown(com.xebialabs.xlrelease.osgi.spring.PluginRuntime)completes, watches whether a plugin's classloader actually becomes collectible within a bounded delay, and logs atERROR- with the plugin's symbolic name and install/teardown timestamps - if it doesn't.Thrown byPluginContextFactory.build(org.osgi.framework.Bundle, com.xebialabs.xlrelease.osgi.spring.PluginManifest, org.springframework.context.support.GenericApplicationContext)when construction fails after the childApplicationContextwas created - carries the partially-builtPluginRuntimeso the caller can route cleanup through the samePluginTeardownused for normal removal, rather thanPluginContextFactoryclosing it internally.Builds a plugin's childAnnotationConfigApplicationContextfrom aPluginManifest+Bundle, parented to the curatedPluginApiParentContext.A single instance is shared between the root hostApplicationContext(as this@Component) and every plugin's curated parent context (PluginApiParentContextregisters the exact same object as a singleton there), mirroringPluginExtensionRegistryImpl's sharing pattern.Host-facing read API for discovering plugin implementations ofHostExtensionPointsubtypes.A single instance is shared between the root hostApplicationContext(as this@Component) and every plugin's curated parent context (PluginApiParentContextregisters the exact same object as a singleton there) - not two copies, one shared reference, so a plugin-side registration is immediately visible to host-side queries.Push counterpart toPluginExtensionRegistryImpl.extensions(Class): a host component that wants to maintain externally-visible derived state (e.g.OSGi-service feeder forPluginExtensionRegistryImpl: a bundle that contributes a Declarative Services component (rather than a Spring plugin context, seePluginContextFactory) implementing one ofHostExtensionPointCatalog's interfaces is discovered here and registered into the same registry, under the sameBundle-SymbolicNamekey, as any Spring-plugin-context extension.The manifest-header contract a bundle must satisfy to be recognized as a "Spring plugin" by the host:Everything the host needs to reference a running plugin instance: the OSGi bundle it came from, its parsed manifest, and its child Spring context.The single, strictly-ordered, fully idempotent teardown procedure used by every plugin removal path - this is the load-bearing safety mechanism of the entire OSGi plugin platform.