Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KAFKA-15069: Refactor plugin scanning logic into ReflectionScanner #13821

Merged
merged 19 commits into from Jul 6, 2023

Conversation

gharris1727
Copy link
Contributor

@gharris1727 gharris1727 commented Jun 6, 2023

In order to support multiple scanning modes, we should refactor the existing scanning mechanism out of the DelegatingClassLoader. This is because KIP-898 will require more functionality that relies on the results of scanning, and it is not appropriate to add this functionality to the DCL itself.

Scanning (and the PluginScanResult) are dependent on the ClassLoader instances which are used to load the plugins, so the protected functions for instantiating classloaders is moved to from Plugins and DelegatingClassLoader to the new PluginClassLoaderFactor and ClassLoaderFactory classes. The setup logic that constructs PluginClassLoaders for each pluginLocation is moved to PluginUtils.pluginSources.

In addition to pulling the existing reflection-based scanning out into a ReflectionScanner and superclass PluginScanner, rename DelegatingClassLoaderTest to PluginScannerTest, because it was primarily testing the plugin scanning.

This test will be expanded in a follow-up to be parameterized, and test the ServiceLoaderScanner in similar fashion to the ReflectionScanner.

To replace DelegatingClassLoaderTest, write a new test targeting the now much smaller scope of the DelegatingClassLoader, using mocked parent and plugin classloaders, as well as mocked plugin scanning logic.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

Signed-off-by: Greg Harris <greg.harris@aiven.io>
This reverts commit 65d876032f9c95f653e657d9fe358ffa192f6d98.
@jlprat jlprat added the connect label Jun 7, 2023
@C0urante
Copy link
Contributor

C0urante commented Jun 7, 2023

@gharris1727 can we start filing Jira tickets for these changes to classloading logic? They're large enough that I don't think MINOR is warranted anymore, and it'd be nice to have a picture of how they fit into the high-level implementation plan for KIP-898.

@gharris1727 gharris1727 changed the title MINOR: Refactor plugin scanning logic into ReflectionScanner and ServiceLoaderScanner KAFKA-15069: Refactor plugin scanning logic into ReflectionScanner and ServiceLoaderScanner Jun 7, 2023
Copy link
Contributor

@C0urante C0urante left a comment

Choose a reason for hiding this comment

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

Thanks Greg! I really like the shape of this and think I can see how this lays the groundwork for KIP-898 better. Left a few questions/thoughts.

Also, even though it's unused in this patch, if we're going to add the ServiceLoaderScanner class, we should also add tests for it. I'd also be fine if we left that class out for now and introduced it in a subsequent PR that starts to make use of it.

Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
…EFINED_VERSION

Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
@@ -325,6 +328,34 @@ public static List<Path> pluginUrls(Path topPath) throws IOException {
return Arrays.asList(archives.toArray(new Path[0]));
}

public static Set<PluginSource> pluginSources(List<Path> pluginLocations, DelegatingClassLoader classLoader, ClassLoaderFactory factory) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason not to generalize the signature, since we don't use any methods specific to the DelegatingClassLoader class?

Suggested change
public static Set<PluginSource> pluginSources(List<Path> pluginLocations, DelegatingClassLoader classLoader, ClassLoaderFactory factory) {
public static Set<PluginSource> pluginSources(List<Path> pluginLocations, ClassLoader classLoader, ClassLoaderFactory factory) {

@@ -104,6 +81,33 @@ public DelegatingClassLoader(List<Path> pluginLocations) {
this(pluginLocations, DelegatingClassLoader.class.getClassLoader());
}

public Set<PluginSource> sources() {
Copy link
Contributor

@C0urante C0urante Jun 29, 2023

Choose a reason for hiding this comment

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

I think it's fine in PluginUtils if we plan on using it in multiple places. Otherwise, we may want to downgrade its visibility and move it into the single class that uses it. Either way, thanks for the change--I think this is an improvement 👍

I'm not a huge fan of how we're using the ClassLoaderFactory class right now, though. I can see the value for it in the Plugins class when both methods are used, but requiring an instance of it in PluginUtils::pluginSources seems like overkill since we don't need access to the newDelegatingClassLoader method.

Could we create a separate PluginClassLoaderFactory interface, have ClassLoaderFactory implement that interface, and change the signature of PluginUtils::pluginSources to accept an instance of that interface instead of a ClassLoaderFactory?

Also, it may be a little unclear to first-time readers why we have the separate ClassLoaderFactory class since it tracks no (instance or static) state and seems at first glance like all of its logic might be a better fit for the PluginUtils class. Can we document in that class that its purpose is to provide a layer of indirection for the purpose of easier mocking in tests?

Finally, we don't have to copy the visibility of the methods that we've extracted into the ClassLoaderFactory class; IMO both of those can and should be made public.

@C0urante
Copy link
Contributor

Thanks Greg! The latest changes look great. A few small comments left about some of the internal APIs we're introducing here. We also still need to either add tests for the service loader scanner, or remove that class from this PR.

Signed-off-by: Greg Harris <greg.harris@aiven.io>
…Test

Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
Signed-off-by: Greg Harris <greg.harris@aiven.io>
@gharris1727 gharris1727 changed the title KAFKA-15069: Refactor plugin scanning logic into ReflectionScanner and ServiceLoaderScanner KAFKA-15069: Refactor plugin scanning logic into ReflectionScanner Jul 6, 2023
@gharris1727
Copy link
Contributor Author

@C0urante Thanks for the helpful comments! The initial version was just-enough to get later stuff working, but the latest version is a much more complete refactor.

We also still need to either add tests for the service loader scanner, or remove that class from this PR.

To properly test the ServiceLoaderScanner, I'll need to add manifests to the TestPlugins. To avoid scope creep, I've moved the ServiceLoaderScanner out of this PR. I'll add it in a follow-up along with the necessary test changes.

This is ready for another pass.

Copy link
Contributor

@C0urante C0urante left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks Greg

@C0urante C0urante merged commit 1b925e9 into apache:trunk Jul 6, 2023
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants