forked from airlift/resolver
-
Notifications
You must be signed in to change notification settings - Fork 7
fix(resolver):Fix classloader issue for Spark/isolated environments #9
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
Open
ShahimSharafudeen
wants to merge
1
commit into
prestodb:master
Choose a base branch
from
ShahimSharafudeen:resolver_1.7_spark_issue_fix
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,6 +90,16 @@ public class ArtifactResolver | |
| .add("http://repo.maven.apache.org/maven2/") | ||
| .build(); | ||
|
|
||
| private static final String MAVEN_REPOSITORY_SYSTEM_CLASS = "org.apache.maven.repository.RepositorySystem"; | ||
| private static final String PLEXUS_CONTAINER_CLASS = "org.codehaus.plexus.DefaultPlexusContainer"; | ||
| private static final String AETHER_REPOSITORY_SYSTEM_CLASS = "org.eclipse.aether.RepositorySystem"; | ||
|
|
||
| /** | ||
| * Cached effective ClassLoader to avoid repeated Class.forName checks on every container() call. | ||
| * Initialized lazily on first access and reused thereafter. | ||
| */ | ||
| private static volatile ClassLoader cachedEffectiveClassLoader; | ||
|
|
||
| private final RepositorySystem repositorySystem; | ||
| private final DefaultRepositorySystemSession repositorySystemSession; | ||
| private final List<RemoteRepository> repositories; | ||
|
|
@@ -327,7 +337,11 @@ private static PlexusContainer container() | |
| { | ||
| // TODO: move off Plexus DI, use Sisu instead | ||
| try { | ||
| ClassWorld classWorld = new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader()); | ||
| // Fix for Spark and other isolated classloader environments: | ||
| // Select an effective ClassLoader by checking multiple candidates to ensure Maven Resolver/Plexus components are discoverable at runtime. | ||
| ClassLoader classLoader = getEffectiveClassLoader(); | ||
|
|
||
| ClassWorld classWorld = new ClassWorld("plexus.core", classLoader); | ||
|
|
||
| ContainerConfiguration cc = new DefaultContainerConfiguration() | ||
| .setClassWorld(classWorld) | ||
|
|
@@ -350,4 +364,78 @@ private static PlexusContainer container() | |
| throw new RuntimeException("Error loading Maven system", e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Determine a ClassLoader that can access Maven Resolver and Plexus classes. | ||
| * Some isolated runtimes (e.g. Spark executors) use a TCCL that cannot see | ||
| * resolver dependencies, so we fall back to the resolver's defining loader. | ||
| */ | ||
| private static ClassLoader getEffectiveClassLoader() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this method should be
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| { | ||
| // First check without synchronization (fast path for already cached value) | ||
| ClassLoader cached = cachedEffectiveClassLoader; | ||
| if (cached != null) { | ||
| return cached; | ||
| } | ||
|
|
||
| // Synchronize for initialization to prevent race conditions | ||
| synchronized (ArtifactResolver.class) { | ||
| // Double-check after acquiring lock | ||
| cached = cachedEffectiveClassLoader; | ||
| if (cached != null) { | ||
| return cached; | ||
| } | ||
|
|
||
| ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); | ||
| if (contextClassLoader != null && canLoadMavenComponents(contextClassLoader)) { | ||
| cachedEffectiveClassLoader = contextClassLoader; | ||
| return cachedEffectiveClassLoader; | ||
| } | ||
|
|
||
| ClassLoader thisClassLoader = ArtifactResolver.class.getClassLoader(); | ||
| if (thisClassLoader != null && canLoadMavenComponents(thisClassLoader)) { | ||
| cachedEffectiveClassLoader = thisClassLoader; | ||
| return cachedEffectiveClassLoader; | ||
| } | ||
|
|
||
| ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); | ||
| if (systemClassLoader != null && canLoadMavenComponents(systemClassLoader)) { | ||
| cachedEffectiveClassLoader = systemClassLoader; | ||
| return cachedEffectiveClassLoader; | ||
| } | ||
|
|
||
| ClassLoader fallback = systemClassLoader != null ? systemClassLoader : thisClassLoader; | ||
| if (fallback == null) { | ||
| throw new IllegalStateException("Unable to determine a valid ClassLoader for Maven component initialization. " + | ||
| "Both system ClassLoader and class ClassLoader are null, and no other ClassLoader can load required Maven components."); | ||
| } | ||
| cachedEffectiveClassLoader = fallback; | ||
|
|
||
| return cachedEffectiveClassLoader; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Verify whether the provided ClassLoader has visibility into essential Maven | ||
| * and Plexus components required for resolver initialization. | ||
| * | ||
| * @param classLoader the ClassLoader to validate | ||
| * @return true if required Maven and Plexus classes are visible to the ClassLoader; | ||
| * false otherwise | ||
| */ | ||
| private static boolean canLoadMavenComponents(ClassLoader classLoader) | ||
| { | ||
| try { | ||
| // Verify visibility of a core Maven repository component | ||
| Class.forName(MAVEN_REPOSITORY_SYSTEM_CLASS, false, classLoader); | ||
| // Verify visibility of the Plexus container used for component discovery | ||
| Class.forName(PLEXUS_CONTAINER_CLASS, false, classLoader); | ||
| // Verify visibility of Maven Resolver API (critical for dependency resolution) | ||
| Class.forName(AETHER_REPOSITORY_SYSTEM_CLASS, false, classLoader); | ||
| return true; | ||
| } | ||
| catch (ClassNotFoundException e) { | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't think we need a long javadoc. I would suggest trimming it down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.