Class PluginLoader
ServiceLoader.
Each plugin JAR ships a service registration file under
META-INF/services/ listing its implementation of
TestDiscovery (and, optionally, SourcePatcher). This loader
walks the classpath, instantiates every registered provider, applies the
run-time TestDiscoveryConfig via configure, and verifies that
every provider declares a unique pluginId().
Lifecycle
Instances are intended to be created once per CLI run and injected into the
Command implementations that need them. The loader itself is
stateless — no instance fields — so a single loader can be shared between
commands that participate in the same orchestration. The lifecycle of the
loaded providers is owned by the caller: a typical usage closes them in a
finally block via closeAll(List).
Thread safety
This class is thread-safe. ServiceLoader.load(Class) resolution is
idempotent per classloader, and no shared mutable state is maintained.
- Since:
- 1.0.0
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidCloses every provider in the list, logging anyIOExceptionatLevel.FINEand continuing so that all providers are attempted.List<org.egothor.methodatlas.api.SourcePatcher> loadPatchers(org.egothor.methodatlas.api.TestDiscoveryConfig config) Loads allSourcePatcherproviders registered viaServiceLoader, configures each one withconfig, and returns them in registration order.List<org.egothor.methodatlas.api.TestDiscovery> loadProviders(org.egothor.methodatlas.api.TestDiscoveryConfig config) Loads allTestDiscoveryproviders registered viaServiceLoader, configures each one withconfig, and returns them in registration order.static voidrequireUniqueDiscoveryIds(List<org.egothor.methodatlas.api.TestDiscovery> providers) Verifies that everyTestDiscoveryprovider in the list has a uniqueTestDiscovery.pluginId().static voidrequireUniquePatcherIds(List<org.egothor.methodatlas.api.SourcePatcher> patchers) Verifies that everySourcePatcherin the list has a uniqueSourcePatcher.pluginId().
-
Constructor Details
-
PluginLoader
public PluginLoader()Creates a new plugin loader. The loader carries no instance state and is safe to share across commands within a single CLI run.
-
-
Method Details
-
loadProviders
public List<org.egothor.methodatlas.api.TestDiscovery> loadProviders(org.egothor.methodatlas.api.TestDiscoveryConfig config) Loads allTestDiscoveryproviders registered viaServiceLoader, configures each one withconfig, and returns them in registration order.The returned providers are open resources. Callers must close them through
closeAll(List)in afinallyblock to release any per-provider resources (file handles, native processes, etc.).Time complexity is
O(p)in the number of providers; the ServiceLoader lookup itself is dominated by classpath scanning.- Parameters:
config- run-time configuration forwarded to every provider viaTestDiscovery.configure(org.egothor.methodatlas.api.TestDiscoveryConfig); must not benull- Returns:
- non-empty list of configured providers in registration order
- Throws:
IllegalStateException- if no providers are found on the classpath, or if two providers share the sameTestDiscovery.pluginId()
-
loadPatchers
public List<org.egothor.methodatlas.api.SourcePatcher> loadPatchers(org.egothor.methodatlas.api.TestDiscoveryConfig config) Loads allSourcePatcherproviders registered viaServiceLoader, configures each one withconfig, and returns them in registration order.Unlike
loadProviders(org.egothor.methodatlas.api.TestDiscoveryConfig), returning an empty list is legitimate: languages that do not support source write-back (such as TypeScript or Python) ship no patcher.- Parameters:
config- run-time configuration forwarded to every patcher viaSourcePatcher.configure(org.egothor.methodatlas.api.TestDiscoveryConfig); must not benull- Returns:
- possibly-empty list of configured patchers in registration order
- Throws:
IllegalStateException- if two patchers share the sameSourcePatcher.pluginId()
-
closeAll
Closes every provider in the list, logging anyIOExceptionatLevel.FINEand continuing so that all providers are attempted.This method never throws: a provider whose
closefails leaves its resources in an indeterminate state, but the orchestration layer always exits cleanly. Failures are observable through the FINE-level log.- Parameters:
providers- list of providers to close; must not benull
-
requireUniqueDiscoveryIds
public static void requireUniqueDiscoveryIds(List<org.egothor.methodatlas.api.TestDiscovery> providers) Verifies that everyTestDiscoveryprovider in the list has a uniqueTestDiscovery.pluginId().This method is
staticbecause it is a pure validation with no instance dependencies — test code calls it directly with handcrafted provider lists, and the instance loader calls it after aServiceLoadersweep. Time complexity isO(p)in the number of providers.- Parameters:
providers- list of providers to validate; must not benull- Throws:
IllegalStateException- if two or more providers share the same id
-
requireUniquePatcherIds
public static void requireUniquePatcherIds(List<org.egothor.methodatlas.api.SourcePatcher> patchers) Verifies that everySourcePatcherin the list has a uniqueSourcePatcher.pluginId().- Parameters:
patchers- list of patchers to validate; must not benull- Throws:
IllegalStateException- if two or more patchers share the same id
-