Support alternative extension implementations#5816
Conversation
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
| return null; | ||
| } | ||
| }) | ||
| .sorted(Comparator.comparing(ExtensionPluginWithContext::isConfigured).reversed()) |
There was a problem hiding this comment.
It would be ideal to have this Comparator in another class so that it can grow over time without having to change this method. And it could have it's own unit tests.
You could create a named bean in PluginCreatorContext.
@Bean(name = "extensionsLoaderComparator")
public Comparator<ExtensionLoader.ExtensionPluginWithContext> extensionsLoaderComparator() {
return Comparator.comparing(ExtensionPluginWithContext::isConfigured).reversed();
}
| private static final ExtensionProvider.Context EMPTY_CONTEXT = new EmptyContext(); | ||
| private final GenericApplicationContext sharedApplicationContext; | ||
| private final GenericApplicationContext coreApplicationContext; | ||
| private Map<Class, Optional<Object>> providers; |
There was a problem hiding this comment.
I think a Set<Class<? extends ExtensionProvider>> should be sufficient. You don't need the value and you can avoid the call to extensionProvider.provideInstance(EMPTY_CONTEXT).
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
| this.pluginErrorsHandler = pluginErrorsHandler; | ||
| } | ||
|
|
||
| ExtensionLoader( |
There was a problem hiding this comment.
Let's only have one constructor.
You can add this to the constructor above:
@Named("extensionsLoaderComparator" final Comparator<ExtensionLoader.ExtensionPluginWithContext> extensionsLoaderComparator
|
|
||
| List<? extends ExtensionPlugin> result = null; | ||
| if (extensionPluginsWithContext != null && extensionPluginsWithContext.size() > 1 && | ||
| extensionsLoaderComparator != null) { |
There was a problem hiding this comment.
I think we don't want this null check. This sorter always needs to be there. We could even add this to the constructor:
this.extensionsLoaderComparator = Objects.requireNonNull(extensionsLoaderComparator);
I think we can just drop the entire conditional.
| return new PluginCreator(pluginConfigurationObservableRegister); | ||
| } | ||
|
|
||
| @Bean(name = "extensionsLoaderComparator") |
There was a problem hiding this comment.
You can add a simple unit test for this in PluginCreatorContextTest (add it if doesn't exist).
| final String expectedPluginName = "test_extension_with_config"; | ||
| when(extensionPluginConfigurationConverter.convert(eq(true), eq(TestExtensionConfig.class), | ||
| anyString())).thenReturn(new TestExtensionConfig()); | ||
| //when(extensionPluginConfigurationConverter.convert(eq(true), eq(TestExtension.class), |
| @BeforeEach | ||
| void setUp() { | ||
| pluginErrorCollector = new PluginErrorCollector(); | ||
| pluginCreatorContext = new PluginCreatorContext(); |
There was a problem hiding this comment.
You could use a simple Comparator that sorts by name. That way these tests are not coupled with the sort logic.
There was a problem hiding this comment.
Yes, but this way we are testing the actual sorting logic. I think this is better.
There was a problem hiding this comment.
That is fine. But, we should have tests for the sort specifically. As the sort logic changes over time it will be much easier to isolate to just the Comparator test.
|
|
||
| private PluginCreatorContext pluginCreatorContext; | ||
|
|
||
| @Mock |
There was a problem hiding this comment.
You are not using this as a mock, so you don't need this annotation.
| private ArgumentCaptor<Collection<PluginError>> pluginErrorsArgumentCaptor; | ||
| private PluginErrorCollector pluginErrorCollector; | ||
|
|
||
| private PluginCreatorContext pluginCreatorContext; |
There was a problem hiding this comment.
You don't need this field. You can move it to a local variable in setUp. Also, you might not need it if you use a different Comparator.
There was a problem hiding this comment.
I think I will keep the same comparator.
|
@kkondaka , Once you address these comments, this should be good to go. I think this is a solid change to extensions. |
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
| @Test | ||
| public void test_extensionsLoaderComparator() { | ||
| Comparator<ExtensionLoader.ExtensionPluginWithContext> extensionsLoaderComparator = pluginCreatorContext.extensionsLoaderComparator(); | ||
| assertNotNull(extensionsLoaderComparator); |
There was a problem hiding this comment.
We should include tests that verify the sorting here. That way we can verify different sort combinations.
You don't have to test using sorts per se.
It could be as simple as these some of these combinations on compareTo:
- Two objects both with isConfigured==true should have compareTo==0
- Two objects both with isConfigured==false should have compareTo==0
- Two objects, one with isConfigured==false and isConfigured==true, compareTo < 0 when true is on the left
- Two objects, one with isConfigured==false and isConfigured==true, compareTo > 0 when true is on the right
There was a problem hiding this comment.
It would be better to put these as different @Test cases, but I'm ok with it.
| @BeforeEach | ||
| void setUp() { | ||
| pluginErrorCollector = new PluginErrorCollector(); | ||
| pluginCreatorContext = new PluginCreatorContext(); |
There was a problem hiding this comment.
That is fine. But, we should have tests for the sort specifically. As the sort logic changes over time it will be much easier to isolate to just the Comparator test.
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
| @Test | ||
| public void test_extensionsLoaderComparator() { | ||
| Comparator<ExtensionLoader.ExtensionPluginWithContext> extensionsLoaderComparator = pluginCreatorContext.extensionsLoaderComparator(); | ||
| assertNotNull(extensionsLoaderComparator); |
There was a problem hiding this comment.
It would be better to put these as different @Test cases, but I'm ok with it.
* Support alternative extension implementations Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> * Addressed review comments and added tests Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> * Addressed review comments and added tests Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> * Addressed review comments Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> * Added tests Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> --------- Signed-off-by: Krishna Kondaka <krishkdk@amazon.com> Signed-off-by: Jonah Calvo <caljonah@amazon.com>
Description
Support alternative extension implementations. This allows multiple implementations for the same extension class with the extension with config provided is preferred over extension(s) without config provided. If multiple extensions with config are provided, the behavior is same as today, which is, it depends on the order in which the extensions are loaded. In future we will have a way to handle this.
Issues Resolved
Resolves #5792
Check List
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.