feat: Add independent extension API versioning and plugin dependencies - #460
gibson9583 wants to merge 4 commits into
Conversation
Allow plugins and connectors to declare a minimum OIE extension API version independently of product releases. Preserve release matching for extensions that do not opt in. Share compatibility checks across installation and launcher loading, with regression tests and the compatibility contract. Validation: 699 tests, 44 ZIP installation cases, launcher filtering, and isolated packaged-helper checks passed. Signed-off-by: gibson9583 <cgibson@outlook.com>
Document new plugin and connector metadata, build dependencies, packaging, installation, restarts, and functional validation. Show migration from release lists, explain separate legacy archives, and link the author guide from the README. Validation: both complete XML templates deserialize and roundtrip with OIE's serializer; local documentation links resolve. Signed-off-by: gibson9583 <cgibson@outlook.com>
Allow extensions to declare required plugins and the engine API in one metadata list. Check the planned installation inventory and reject provider changes that would break enabled consumers. Keep legacy declarations and plugin initialization behavior intact. Document new extensions, migration, and dependency validation. Validation: 748 tests; 15 isolated launcher scenarios. Signed-off-by: gibson9583 <cgibson@outlook.com>
c74ab97 to
e95dfde
Compare
mgaffigan
left a comment
There was a problem hiding this comment.
I like the direction. Key notes:
- Avoid implementing a custom deserialization parser
- Simplify the dependency graph and validation - we don't need to handle arbitrary graphs; the real world is not as messy as this contemplates.
- Pull out the plugin install from the service endpoint
Honestly, fine approving as is. No blocking issues - just maintainability comments. Given the test complement, I'm sure it does the thing.
| private String name; | ||
| private String author; | ||
| private String mirthVersion; | ||
| private String minExtensionApiVersion; |
There was a problem hiding this comment.
This and other "minExtensionApiVersion" commentary can be removed if unused.
There was a problem hiding this comment.
Can we avoid all of this? The classpath is the claspath, we can't meaningfully affect it. Gate extensions on install (and maybe in the UI). We can't be duplicating the logic of xstream for deserialization.
There was a problem hiding this comment.
This should be simplified. Practically, we have ten layers of dependencies (max). Asserting that it does not use the callstack is intellectually pure, but makes it very hard to reason about. We do this once a month per server. Who cares about perf?
There was a problem hiding this comment.
This is quite complex - can we pull out into simpler units that can be tested without a complex object graph?
Use the engine serializer and recursive dependency validation. Remove redundant API metadata and duplicate launcher compatibility parsing. Extract archive installation into a testable helper while preserving planned-inventory checks and package rollback. Document the single dependency format and startup classpath behavior. Validation: 746 tests, packaged launcher checks, 10,000 graph orderings. Signed-off-by: gibson9583 <cgibson@outlook.com>
Extensions currently list compatible engine releases through
mirthVersion, requiring metadata updates even when the extension API has not changed. This PR adds an independently versioned OIE extension API so authors can reuse an archive across engine releases that preserve that API.Plugins and connectors can declare requirements in one dependency list:
The initial engine API version is 1.0.0, independent of the product release number. Plugin requirements use the provider's exact metadata name and its own
pluginVersion. Both require numericmajor.minor.patchversions: the available version must meet the minimum and have the same major number. Descriptors without anengine-apidependency retain legacymirthVersionmatching.Startup validation runs before metadata is exposed to engine and Administrator hooks. The launcher only discovers enabled extension libraries; those libraries can already be on the shared classpath when an extension is rejected. Compatibility checks do not provide classloader isolation. Existing initialization weights and conditions remain responsible for startup order; dependency acceptance does not guarantee that a provider's service initialized successfully.
Extensions targeting engines that predate dependency-list support need a separate legacy archive.
Validation:
./gradlew build -PdisableSigning=truewith JDK 17 passed all 746 tests. Additional checks covered 10,000 shuffled dependency inventories, packaged launcher discovery without engine compatibility classes, XML type overrides, and promotion/rollback failures with preserved recovery data.