/* * 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.functional.junit4; import static com.google.common.collect.ImmutableList.copyOf; import static org.apache.commons.lang.ArrayUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isBlank; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.initialiseIfNeeded; import static org.mule.runtime.core.util.IOUtils.getResourceAsUrl; import static org.springframework.util.ReflectionUtils.findMethod; import org.mule.runtime.core.DefaultMuleContext; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.config.ConfigurationBuilder; import org.mule.runtime.core.api.extension.ExtensionManager; import org.mule.runtime.core.config.builders.AbstractConfigurationBuilder; import org.mule.runtime.extension.api.loader.ExtensionModelLoader; import org.mule.runtime.extension.api.resources.GeneratedResource; import org.mule.runtime.extension.api.resources.ResourcesGenerator; import org.mule.runtime.module.extension.internal.loader.java.DefaultJavaExtensionModelLoader; import org.mule.runtime.module.extension.internal.manager.DefaultExtensionManager; import org.mule.test.runner.infrastructure.ExtensionsTestInfrastructureDiscoverer; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.util.List; import org.apache.commons.io.FileUtils; /** * Base test class for {@link FunctionalTestCase}s that make use of components generated through the extensions API. * <p/> * The value added by this class in comparison to a traditional {@link FunctionalTestCase} is that before creating the * {@link MuleContext}, it creates a {@link ExtensionManager} and automatically registers extensions pointed by * {@link #getAnnotatedExtensionClasses()} methods. * <p/> * Once extensions are registered, a {@link ResourcesGenerator} is used to automatically generate any backing resources needed * (XSD schemas, spring bundles, etc). * <p/> * In this way, the user experience is greatly simplified when running the test either through an IDE or build tool such as maven * or gradle. * <p/> * Since this class extends {@link FunctionalTestCase}, a new {@link MuleContext} is created per each test. That also means that a * new {@link ExtensionManager} is created per test. * * @since 3.7.0 */ public abstract class ExtensionFunctionalTestCase extends FunctionalTestCase { private ExtensionManager extensionManager; /** * Implement this method to limit the amount of extensions initialised by providing the annotated classes which define the * extensions that you actually want to use for this test. Returning a {@code null} or empty array forces the * {@link ExtensionManager} to perform a full classpath discovery. Default implementation of this method returns {@code null}. */ protected Class<?>[] getAnnotatedExtensionClasses() { return null; } /** * Adds a {@link ConfigurationBuilder} that sets the {@link #extensionManager} into the {@link #muleContext}. This * {@link ConfigurationBuilder} is set as the first element of the {@code builders} {@link List} * * @param builders the list of {@link ConfigurationBuilder}s that will be used to initialise the {@link #muleContext} */ @Override //TODO - MULE-11119: Make final again once we can add the HTTP service injection as the scehduler's is protected void addBuilders(List<ConfigurationBuilder> builders) { super.addBuilders(builders); builders.add(0, new AbstractConfigurationBuilder() { @Override protected void doConfigure(MuleContext muleContext) throws Exception { createExtensionsManager(muleContext); } }); } private void createExtensionsManager(MuleContext muleContext) throws Exception { extensionManager = new DefaultExtensionManager(); File generatedResourcesDirectory = getGenerationTargetDirectory(); ((DefaultMuleContext) muleContext).setExtensionManager(extensionManager); initialiseIfNeeded(extensionManager, muleContext); ExtensionsTestInfrastructureDiscoverer discoverer = new ExtensionsTestInfrastructureDiscoverer(extensionManager); for (Class<?> annotatedClass : getAnnotatedExtensionClasses()) { discoverer.discoverExtension(annotatedClass, getExtensionModelLoader()); } generateResourcesAndAddToClasspath(generatedResourcesDirectory, copyOf(discoverer .generateDslResources(generatedResourcesDirectory))); } private void generateResourcesAndAddToClasspath(File generatedResourcesDirectory, List<GeneratedResource> resources) throws Exception { ClassLoader cl = getClass().getClassLoader(); Method method = findMethod(cl.getClass(), "addURL", URL.class); method.setAccessible(true); for (GeneratedResource resource : resources) { URL generatedResourceURL = new File(generatedResourcesDirectory, resource.getPath()).toURI().toURL(); method.invoke(cl, generatedResourceURL); } } private File getGenerationTargetDirectory() { URL url = getResourceAsUrl(getEffectiveConfigFile(), getClass(), true, true); File targetDirectory = new File(FileUtils.toFile(url).getParentFile(), "META-INF"); if (!targetDirectory.exists() && !targetDirectory.mkdir()) { throw new RuntimeException("Could not create target directory " + targetDirectory.getAbsolutePath()); } return targetDirectory; } private String getEffectiveConfigFile() { String configFile = getConfigFile(); if (!isBlank(configFile)) { return configFile; } configFile = getConfigFileFromSplittable(getConfigurationResources()); if (!isBlank(configFile)) { return configFile; } configFile = getConfigFileFromSplittable(getConfigResources()); if (!isBlank(configFile)) { return configFile; } String[] configFiles = getConfigFiles(); if (!isEmpty(configFiles)) { return configFiles[0].trim(); } throw new IllegalArgumentException("No valid config file was specified"); } private String getConfigFileFromSplittable(String configFile) { if (!isBlank(configFile)) { return configFile.split(",")[0].trim(); } return null; } protected ExtensionModelLoader getExtensionModelLoader() { return new DefaultJavaExtensionModelLoader(); } }