/*
* 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.test.runner.api;
import static org.mule.runtime.api.util.Preconditions.checkNotNull;
import static org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor.MULE_PLUGIN_CLASSIFIER;
import static org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor.MULE_PLUGIN_JSON;
import static org.mule.test.runner.api.ArtifactClassificationType.APPLICATION;
import static org.mule.test.runner.api.ArtifactClassificationType.MODULE;
import static org.mule.test.runner.api.ArtifactClassificationType.PLUGIN;
import org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.resolution.ArtifactResolutionException;
/**
* Resolves the {@link ArtifactClassificationType} for an {@link org.eclipse.aether.artifact.Artifact}.
*
* @since 4.0
*/
public class ArtifactClassificationTypeResolver {
private static final String MULE_EXTENSION_CLASSIFIER = "mule-extension";
private static final String MULE_MODULE_PROPERTIES = "META-INF/mule-module.properties";
private static final String PLUGIN_PROPERTIES = "plugin.properties";
private static final String JAR_EXTENSION = "jar";
private DependencyResolver dependencyResolver;
/**
* Creates an instance of this resolver.
*
* @param dependencyResolver {@link DependencyResolver} to get artifact output. Non null.
*/
public ArtifactClassificationTypeResolver(DependencyResolver dependencyResolver) {
checkNotNull(dependencyResolver, "dependencyResolver cannot be null");
this.dependencyResolver = dependencyResolver;
}
/**
* Resolves the {@link ArtifactClassificationType} for the artifact.
*
* @param artifact the {@link Artifact} to get its {@link ArtifactClassificationType}
* @return {@link ArtifactClassificationType} for the artifact given
*/
public ArtifactClassificationType resolveArtifactClassificationType(Artifact artifact) {
try (URLClassLoader artifactClassLoader = createArtifactClassLoader(artifact)) {
if (isMulePlugin(artifact, artifactClassLoader)) {
return PLUGIN;
}
if (isMuleModule(artifactClassLoader)) {
return MODULE;
}
return APPLICATION;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* @param artifact {@link Artifact} to check if it is a plugin
* @param artifactClassLoader {@link ClassLoader} for the given artifact
* @return true if it is classified as {@value ArtifactPluginDescriptor#MULE_PLUGIN_CLASSIFIER} or {@value #MULE_EXTENSION_CLASSIFIER} or it has a
* {@value ArtifactPluginDescriptor#MULE_PLUGIN_JSON} file.
*/
private boolean isMulePlugin(Artifact artifact, ClassLoader artifactClassLoader) {
return artifact.getExtension().equals(MULE_PLUGIN_CLASSIFIER) || artifact.getExtension().equals(MULE_EXTENSION_CLASSIFIER)
|| hasResource(artifactClassLoader, MULE_PLUGIN_JSON);
}
/**
* @param artifactClassLoader {@link ClassLoader} for the given artifact.
* @return true if it has a {@value #MULE_MODULE_PROPERTIES} file.
*/
private boolean isMuleModule(ClassLoader artifactClassLoader) {
return hasResource(artifactClassLoader, MULE_MODULE_PROPERTIES);
}
/**
* Checks if the {@link ClassLoader} has the resource given.
*
* @param classLoader {@link ClassLoader} in order to check if the resource exists, can be null.
* @param resource name of the resource to look for.
* @return
*/
private boolean hasResource(ClassLoader classLoader, String resource) {
if (classLoader == null) {
return false;
}
return classLoader.getResource(resource) != null;
}
private URLClassLoader createArtifactClassLoader(Artifact artifact) {
try {
return new URLClassLoader(new URL[] {resolveRootArtifactUrls(artifact)}, null);
} catch (ArtifactResolutionException e) {
return null;
}
}
/**
* Resolves the rootArtifact {@link URL}s resources to be added to class loader.
*
* @param artifact {@link Artifact} being classified
* @return {@link List} of {@link URL}s to be added to class loader
* @throws {@link ArtifactResolutionException} if the artifact doesn't have a JAR output file (target/classes when not packaged)
*/
private URL resolveRootArtifactUrls(Artifact artifact) throws ArtifactResolutionException {
final DefaultArtifact jarArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(),
JAR_EXTENSION, JAR_EXTENSION, artifact.getVersion());
try {
return dependencyResolver.resolveArtifact(jarArtifact).getArtifact().getFile().toURI().toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException("Couldn't generate the URL for artifact: " + artifact);
}
}
}