Skip to content

feat: Add independent extension API versioning and plugin dependencies - #460

Open
gibson9583 wants to merge 4 commits into
OpenIntegrationEngine:mainfrom
gibson9583:feature/extension-api-version
Open

gibson9583 wants to merge 4 commits into
OpenIntegrationEngine:mainfrom
gibson9583:feature/extension-api-version

Conversation

@gibson9583

@gibson9583 gibson9583 commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

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:

<dependencies>
    <dependency type="engine-api" minVersion="1.0.0"/>
    <dependency type="plugin" name="Provider Plugin" minVersion="2.1.0"/>
</dependencies>

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 numeric major.minor.patch versions: the available version must meet the minimum and have the same major number. Descriptors without an engine-api dependency retain legacy mirthVersion matching.

  • Use the existing XML serializer and a recursive dependency walk for installation and startup checks. Missing, disabled, incompatible, ambiguous, or circular prerequisites reject affected extensions.
  • Validate the complete next-start inventory, including pending removals, staged packages, and every incoming descriptor. Reject provider changes that would break a currently valid, enabled consumer.
  • Keep archive parsing, extraction, staging, and rollback in an independently testable installer. Replace complete packages and retain recovery files if rollback fails.
  • Document new extensions, migration, packaging, API version policy, and validation in the extension author guide.

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=true with 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.

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>
@gibson9583
gibson9583 force-pushed the feature/extension-api-version branch from c74ab97 to e95dfde Compare September 21, 2026 19:49
@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Test Results

130 files  + 7  130 suites  +7   2m 9s ⏱️ +20s
748 tests +58  748 ✅ +58  0 💤 ±0  0 ❌ ±0 
760 runs  +58  760 ✅ +58  0 💤 ±0  0 ❌ ±0 

Results for commit a3894a6. ± Comparison against base commit 9359d9a.

♻️ This comment has been updated with latest results.

@mgaffigan mgaffigan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and other "minExtensionApiVersion" commentary can be removed if unused.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants