Skip to content

Add support for extensions to depend upon other extensions#6012

Merged
dlvenable merged 1 commit into
opensearch-project:mainfrom
graytaylor0:ExtensionsChange
Aug 23, 2025
Merged

Add support for extensions to depend upon other extensions#6012
dlvenable merged 1 commit into
opensearch-project:mainfrom
graytaylor0:ExtensionsChange

Conversation

@graytaylor0

@graytaylor0 graytaylor0 commented Aug 22, 2025

Copy link
Copy Markdown
Member

Description

This change allows for extensions to depend on other extensions by loading them in the correct order based on the classes they provide and their dependencies.

The plugins will be loaded in the order by checking

  1. If the plugin is configured (configured plugins get priority)
  2. If one plugin depends on another, that plugin will be loaded after the one it depends on

Tested by loading aws secrets plugin with AwsCredentialsSupplier and verifying that the supplier is accessible

Issues Resolved

Resolves #2825

Check List

  • New functionality includes testing.
  • New functionality has a documentation issue. Please link to it in this PR.
    • New functionality has javadoc added
  • Commits are signed with a real name per the DCO

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: Taylor Gray <tylgry@amazon.com>
* Data Prepper as an extension plugin. Everything starts from here.
*/
@DataPrepperExtensionPlugin(modelType = AwsPluginConfig.class, rootKeyJsonPath = "/aws/configurations")
@ExtensionProvides(providedClasses = {AwsCredentialsSupplier.class})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is this needed? AwsCredentialsSupplier is not an extension class, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

AwsCredentialsSupplier is not an extension class. It is provided by an extension class. This is declaring that this particular extension provides it.

@dlvenable dlvenable left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @graytaylor0 !


@Override
public <T> T getExtensionProvider(final Class<T> type) {
sharedApplicationContext.refresh();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We found that multiple calls to refresh() will fail. So this solution only works with one dependency. This is fine for now, but we need to remember to fix this.

* Data Prepper as an extension plugin. Everything starts from here.
*/
@DataPrepperExtensionPlugin(modelType = AwsPluginConfig.class, rootKeyJsonPath = "/aws/configurations")
@ExtensionProvides(providedClasses = {AwsCredentialsSupplier.class})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

AwsCredentialsSupplier is not an extension class. It is provided by an extension class. This is declaring that this particular extension provides it.

public class ExtensionPluginWithContext {
ExtensionPlugin extensionPlugin;
boolean configured;
Class<?>[] dependentClasses;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These can be final (along with the two above).

return (extensionOne, extensionTwo) -> {
// First, compare by configuration status (configured ones first)
int configCompare = Boolean.compare(extensionTwo.isConfigured(), extensionOne.isConfigured());
if (configCompare != 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is probably not the final sorting. It may be the case a configured depends on a non-configured. In which case the dependency will not exist. But, we can handle this later.

@dlvenable

Copy link
Copy Markdown
Member

We may be able to improve the Spring issue and even let Spring do the ordering by making use of Spring's support to register beans using a Supplier instead of a concrete object.

If we move the <T> T getExtensionProvider(final Class<T> type) method to ExtensionProvider.Context we may be able to simplify this.

interface Context {
        <T> T getExtensionProvider(final Class<T> type);
    }

The thing I'm unsure of is how to tell Spring of the dependency between the two.

@dlvenable dlvenable merged commit decca13 into opensearch-project:main Aug 23, 2025
45 of 47 checks passed
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.

Allow extensions to depend upon other extensions

3 participants