/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.deployment.model.internal.application;
import static java.lang.Thread.currentThread;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import org.mule.runtime.api.exception.MuleRuntimeException;
import org.mule.runtime.deployment.model.api.application.ApplicationClassLoader;
import org.mule.runtime.deployment.model.api.application.ApplicationDescriptor;
import org.mule.runtime.deployment.model.internal.nativelib.NativeLibraryFinder;
import org.mule.runtime.module.artifact.classloader.ArtifactClassLoader;
import org.mule.runtime.module.artifact.classloader.ClassLoaderLookupPolicy;
import org.mule.runtime.module.artifact.classloader.MuleDeployableArtifactClassLoader;
import org.mule.runtime.module.artifact.descriptor.ArtifactDescriptor;
import org.mule.runtime.module.artifact.descriptor.ClassLoaderModel;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MuleApplicationClassLoader extends MuleDeployableArtifactClassLoader implements ApplicationClassLoader {
static {
registerAsParallelCapable();
}
private NativeLibraryFinder nativeLibraryFinder;
public MuleApplicationClassLoader(String artifactId, ArtifactDescriptor artifactDescriptor, ClassLoader parentCl,
NativeLibraryFinder nativeLibraryFinder, List<URL> urls,
ClassLoaderLookupPolicy lookupPolicy, List<ArtifactClassLoader> artifactPluginClassLoaders) {
super(artifactId, artifactDescriptor, urls.toArray(new URL[0]), parentCl, lookupPolicy, artifactPluginClassLoaders);
this.nativeLibraryFinder = nativeLibraryFinder;
}
@Override
protected String findLibrary(String name) {
String libraryPath = super.findLibrary(name);
libraryPath = nativeLibraryFinder.findLibrary(name, libraryPath);
return libraryPath;
}
@Override
protected String[] getLocalResourceLocations() {
// Always the first element corresponds to the application's classes folder
ClassLoaderModel classLoaderModel = this.<ApplicationDescriptor>getArtifactDescriptor().getClassLoaderModel();
return new String[] {classLoaderModel.getUrls()[0].getFile()};
}
/**
* Resolves the plugin classloader of the thread context classloader artifact.
* <p>
* If that classloader doesn't contain plugins, the current context classloader is returned.
*
* @return the plugin classloader of the current thread context artifact.
*/
public static List<ClassLoader> resolveContextArtifactPluginClassLoaders() {
// TODO MULE-12254
// When running the tests, the classloader hierarchy is build with the launcher, but when executing here we are with the
// container.
// This is why this reflection bloat is required.
final Method getArtifactPluginClassLoaders;
try {
getArtifactPluginClassLoaders =
currentThread().getContextClassLoader().getClass().getMethod("getArtifactPluginClassLoaders");
} catch (NoSuchMethodException | SecurityException e) {
return singletonList(currentThread().getContextClassLoader());
}
final List artifactPluginClassLoaders;
try {
artifactPluginClassLoaders = (List) getArtifactPluginClassLoaders.invoke(currentThread().getContextClassLoader());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new MuleRuntimeException(e);
}
final List<ClassLoader> classLoaders =
new ArrayList<ClassLoader>((List<ClassLoader>) artifactPluginClassLoaders.stream().map(acl -> {
try {
return acl.getClass().getMethod("getClassLoader").invoke(acl);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
throw new MuleRuntimeException(e);
}
}).collect(toList()));
// TODO MULE-12255 Don't add the context classlaoder, it won't be needed when the test namespace parser is in a plugin rather
// than in the app.
classLoaders.add(currentThread().getContextClassLoader());
return classLoaders;
}
}