package org.mockserver.maven; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang3.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugins.annotations.Parameter; import org.mockserver.initialize.ExpectationInitializer; import java.io.File; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.List; /** * @author jamesdbloom * * @plexus.component role="org.codehaus.plexus.component.configurator.ComponentConfigurator" * role-hint="include-project-dependencies" * @plexus.requirement role="org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup" * role-hint="default" * @requiresDependencyCollection * @requiresDependencyResolution */ public abstract class MockServerAbstractMojo extends AbstractMojo { /** * The port to run MockServer on */ @Parameter(property = "mockserver.serverPort", defaultValue = "-1") protected int serverPort = -1; /** * The port to run the proxy on */ @Parameter(property = "mockserver.proxyPort", defaultValue = "-1") protected int proxyPort = -1; /** * Timeout to wait before stopping MockServer, to run MockServer indefinitely do not set a value */ @Parameter(property = "mockserver.timeout") protected int timeout; /** * Logging level */ @Parameter(property = "mockserver.logLevel", defaultValue = "INFO") protected String logLevel; /** * Skip the plugin execution completely */ @Parameter(property = "mockserver.skip", defaultValue = "false") protected boolean skip; /** * If true the console of the forked JVM will be piped to the Maven console */ @Parameter(property = "mockserver.pipeLogToConsole", defaultValue = "false") protected boolean pipeLogToConsole; /** * To enable the creation of default expectations that are generic across all tests or mocking scenarios a class can be specified * to initialize expectations in the MockServer, this class must implement org.mockserver.initialize.ExpectationInitializer interface, * the initializeExpectations(MockServerClient mockServerClient) method will be called once the MockServer has been started (but ONLY * if serverPort has been set), however it should be noted that it is generally better practice to create all expectations locally in * each test (or test class) for clarity, simplicity and to avoid brittle tests */ @Parameter(property = "mockserver.initializationClass") protected String initializationClass; /** * The main classpath location of the project using this plugin */ @Parameter(property = "project.compileClasspathElements", required = true, readonly = true) protected List<String> compileClasspath; /** * The test classpath location of the project using this plugin */ @Parameter(property = "project.testClasspathElements", required = true, readonly = true) protected List<String> testClasspath; /** * The plugin dependencies */ @Parameter(property = "pluginDescriptor.plugin.dependencies", required = true, readonly = true) protected List<Dependency> dependencies; /** * The plugin dependencies */ @Parameter(property = "pluginDescriptor.artifacts", required = true, readonly = true) protected List<Artifact> pluginArtifacts; /** * Holds reference to jetty across plugin execution */ @VisibleForTesting protected static InstanceHolder embeddedJettyHolder; protected InstanceHolder getEmbeddedJettyHolder() { if (embeddedJettyHolder == null) { // create on demand to avoid log creation for skipped plugins embeddedJettyHolder = new InstanceHolder(); } return embeddedJettyHolder; } protected ExpectationInitializer createInitializer() { try { ClassLoader contextClassLoader = setupClasspath(); if (contextClassLoader != null && StringUtils.isNotEmpty(initializationClass)) { Constructor<?> initializerClassConstructor = contextClassLoader.loadClass(initializationClass).getDeclaredConstructor(); Object expectationInitializer = initializerClassConstructor.newInstance(); if (expectationInitializer instanceof ExpectationInitializer) { return (ExpectationInitializer) expectationInitializer; } } } catch (Exception e) { throw new RuntimeException(e); } return null; } private ClassLoader setupClasspath() throws MalformedURLException { if (compileClasspath != null && testClasspath != null) { URL[] urls = new URL[compileClasspath.size() + testClasspath.size()]; for (int i = 0; i < compileClasspath.size(); i++) { urls[i] = new File(compileClasspath.get(i)).toURI().toURL(); } for (int i = compileClasspath.size(); i < compileClasspath.size() + testClasspath.size(); i++) { urls[i] = new File(testClasspath.get(i - compileClasspath.size())).toURI().toURL(); } ClassLoader contextClassLoader = URLClassLoader.newInstance(urls, Thread.currentThread().getContextClassLoader()); Thread.currentThread().setContextClassLoader(contextClassLoader); return contextClassLoader; } return null; } }