/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/AbstractProductHandlerMojo.java
Java | 946 lines | 491 code | 134 blank | 321 comment | 70 complexity | 54867e37347d0bf506b0927c1d89c4aa MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
- package com.atlassian.maven.plugins.amps;
- import com.atlassian.maven.plugins.amps.product.ProductHandler;
- import com.atlassian.maven.plugins.amps.util.ArtifactRetriever;
- import com.google.common.annotations.VisibleForTesting;
- import org.apache.maven.artifact.Artifact;
- import org.apache.maven.artifact.repository.ArtifactRepository;
- import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
- import org.apache.maven.model.Resource;
- import org.apache.maven.plugin.MojoExecutionException;
- import org.apache.maven.plugin.MojoFailureException;
- import org.apache.maven.plugins.annotations.Component;
- import org.apache.maven.plugins.annotations.Parameter;
- import org.apache.maven.project.MavenProject;
- import javax.annotation.Nonnull;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- import java.util.Properties;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Future;
- import java.util.concurrent.TimeoutException;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_DEV_TOOLBOX_VERSION;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_PDE_VERSION;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_PDK_VERSION;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_PLUGIN_VIEWER_VERSION;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_PRODUCT_SHUTDOWN_TIMEOUT;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_PRODUCT_STARTUP_TIMEOUT;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_QUICK_RELOAD_VERSION;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_SERVER;
- import static com.atlassian.maven.plugins.amps.product.AmpsDefaults.DEFAULT_WEB_CONSOLE_VERSION;
- import static com.atlassian.maven.plugins.amps.util.ProductHandlerUtil.awaitStateChange;
- import static com.atlassian.maven.plugins.amps.util.ProductHandlerUtil.toArtifacts;
- import static com.atlassian.maven.plugins.amps.util.ProjectUtils.getReactorArtifact;
- import static com.atlassian.maven.plugins.amps.util.ProjectUtils.shouldDeployTestJar;
- import static java.lang.String.join;
- import static java.lang.Thread.currentThread;
- import static java.util.Collections.reverse;
- import static java.util.Collections.singletonList;
- import static java.util.Collections.unmodifiableList;
- import static java.util.Locale.ENGLISH;
- import static java.util.concurrent.Executors.newFixedThreadPool;
- import static java.util.concurrent.TimeUnit.MILLISECONDS;
- import static java.util.concurrent.TimeUnit.NANOSECONDS;
- import static org.apache.commons.lang3.StringUtils.split;
- import static org.apache.commons.lang3.StringUtils.trim;
- import static org.apache.commons.lang3.StringUtils.trimToEmpty;
- /**
- * Base class for webapp Mojos.
- */
- @SuppressWarnings("FieldMayBeFinal")
- public abstract class AbstractProductHandlerMojo extends AbstractProductAwareMojo {
- protected static final String ATLASSIAN_TEST_RUNNER_VERSION = "2.0.2";
- protected static final String NO_TEST_GROUP = "__no_test_group__";
- private static final String JUNIT_GROUP_ID = "org.apache.servicemix.bundles";
- private static final String JUNIT_ARTIFACT_ID = "org.apache.servicemix.bundles.junit";
- private static final String JUNIT_VERSION = "4.12_1";
- private static final String TESTRUNNER_GROUP_ID = "com.atlassian.plugins";
- private static final String TESTRUNNER_ARTIFACT_ID = "atlassian-plugins-osgi-testrunner";
- private static final String TESTRUNNER_BUNDLE_ARTIFACT_ID = "atlassian-plugins-osgi-testrunner-bundle";
- // SSL/https defaults
- public static final String DEFAULT_HTTPS_KEYSTOREFILE = "${user.home}/.keystore";
- public static final String DEFAULT_HTTPS_KEYSTOREPASS = "changeit";
- public static final String DEFAULT_HTTPS_KEYALIAS = "tomcat";
- public static final String DEFAULT_HTTP_SECURE = "true";
- public static final String DEFAULT_HTTPS_SSL_PROTOCOL = "TLS";
- public static final String DEFAULT_HTTPS_CLIENTAUTH = "false";
- public static final String DEFAULT_HTTPS_PORT = "0";
- @Component
- private RepositoryMetadataManager repositoryMetadataManager;
- // ------ start inline product context
- /**
- * The artifacts to deploy for the test console if needed.
- */
- private final List<ProductArtifact> testFrameworkPlugins = new ArrayList<>();
- /**
- * The Cargo ID of the container in which to start the product.
- */
- @Parameter(property = "container")
- private String containerId;
- /**
- * The Maven coordinates of the servlet container to run in, if {@code containerId} is not specified or is
- * literally equal to {@code "customContainerArtifact"}. Expected to be of the form
- * {@code groupId:artifactId:version[:packaging][:classifier]}.
- */
- @Parameter(property = "customContainerArtifact")
- private String customContainerArtifact;
- /**
- * The HTTP port for the servlet container.
- */
- @Parameter(property = "http.port", defaultValue = "0")
- private int httpPort;
- /**
- * The AJP port for Cargo to communicate with the servlet container.
- */
- @Parameter(property = "ajp.port", defaultValue = "8009") // Cargo's default is 8009
- private int ajpPort;
- /**
- * Whether the product should be started with HTTPS.
- */
- @Parameter(property = "use.https", defaultValue = "false")
- private boolean useHttps;
- /**
- * The HTTPS port for the servlet container.
- */
- @Parameter(property = "https.port", defaultValue = DEFAULT_HTTPS_PORT)
- private int httpsPort;
- /**
- * The SSL certificate chain option.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.clientAuth", defaultValue = DEFAULT_HTTPS_CLIENTAUTH)
- private String httpsClientAuth;
- /**
- * The SSL protocol to use.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.sslProtocol", defaultValue = DEFAULT_HTTPS_SSL_PROTOCOL)
- private String httpsSslProtocol;
- /**
- * The pathname of the keystore file.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.keystoreFile", defaultValue = DEFAULT_HTTPS_KEYSTOREFILE)
- private String httpsKeystoreFile;
- /**
- * The password to use to access the keypass store.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.keystorePass", defaultValue = DEFAULT_HTTPS_KEYSTOREPASS)
- private String httpsKeystorePass;
- /**
- * The alias of the certificate to use.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.keyAlias", defaultValue = DEFAULT_HTTPS_KEYALIAS)
- private String httpsKeyAlias;
- /**
- * Whether the HTTP container is secured.
- *
- * @since 5.0.4
- */
- @Parameter(property = "https.httpSecure", defaultValue = DEFAULT_HTTP_SECURE)
- private boolean httpsHttpSecure;
- /**
- * The product's context path.
- */
- @Parameter(property = "context.path")
- protected String contextPath;
- /**
- * The hostname of the server running the product.
- */
- @Parameter(property = "server")
- protected String server;
- /**
- * The version of the product.
- */
- @Parameter(property = "product.version")
- private String productVersion;
- /**
- * Any JVM arguments to pass to Cargo.
- */
- @Parameter(property = "jvmargs")
- protected String jvmArgs;
- /**
- * The product startup timeout in milliseconds.
- */
- @Parameter(property = "product.start.timeout")
- private int startupTimeout;
- /**
- * The product shutdown timeout in milliseconds.
- */
- @Parameter(property = "product.stop.timeout")
- private int shutdownTimeout;
- /**
- * The {@code systemProperties} that Cargo should apply when starting the servlet container.
- *
- * @deprecated Since 3.2, use systemPropertyVariables instead
- */
- @Parameter
- @Deprecated
- protected Properties systemProperties = new Properties();
- /**
- * The {@code systemProperties} that Cargo should apply when starting the servlet container, using a more familiar
- * syntax.
- *
- * @since 3.2
- */
- @Parameter
- protected Map<String, Object> systemPropertyVariables = new HashMap<>();
- /**
- * The full path of a custom log4j configuration file, in Java properties format. For example, set this to
- * {@code ${basedir}/src/test/resources/my-custom-log4j.properties} to remain location-independent. AMPS
- * will configure the product's loggers using this file, instead of the file that ships with the product.
- */
- @Parameter
- private File log4jProperties;
- /**
- * The test resources version.
- *
- * @deprecated Since 3.0-beta2, use product.data.version
- */
- @Deprecated
- @Parameter(property = "test.resources.version")
- private String testResourcesVersion;
- /**
- * The test resources version.
- */
- @Parameter(property = "product.data.version")
- private String productDataVersion;
- /**
- * The path to a custom test resources zip.
- */
- @Parameter(property = "product.data.path")
- private String productDataPath;
- /**
- * The path to a directory with home directory overrides.
- */
- @Parameter(property = "product.data.overrides.path")
- private String productDataOverridesPath;
- /**
- * Whether the DevToolbox should be enabled.
- */
- @Parameter(property = "devtoolbox.enable", defaultValue = "true")
- private boolean enableDevToolbox;
- /**
- * The version of DevToolbox to bundle.
- */
- @Parameter(property = "devtoolbox.version", defaultValue = DEFAULT_DEV_TOOLBOX_VERSION)
- private String devToolboxVersion;
- /**
- * Whether to enable the QuickReload plugin.
- */
- @Parameter(property = "quickreload.enable", defaultValue = "false")
- private boolean enableQuickReload;
- /**
- * The version of QuickReload to use.
- */
- @Parameter(property = "quickreload.version", defaultValue = DEFAULT_QUICK_RELOAD_VERSION)
- private String quickReloadVersion;
- /**
- * Whether the PluginViewer should be enabled.
- */
- @Parameter(property = "viewer.enable", defaultValue = "false")
- private boolean enablePluginViewer;
- /**
- * The version of the PluginViewer to use.
- */
- @Parameter(property = "viewer.version", defaultValue = DEFAULT_PLUGIN_VIEWER_VERSION)
- private String pluginViewerVersion;
- /**
- * Whether the Plugin Data Editor should be enabled.
- */
- @Parameter(property = "pde.enable", defaultValue = "true")
- private boolean enablePde;
- /**
- * The version of the Plugin Data Editor to use.
- */
- @Parameter(property = "pde.version", defaultValue = DEFAULT_PDE_VERSION)
- private String pdeVersion;
- /**
- * The applications to install into the product.
- */
- @Parameter
- private List<Application> applications = new ArrayList<>();
- /**
- * The plugins to load into the product.
- */
- @Parameter
- private List<ProductArtifact> pluginArtifacts = new ArrayList<>();
- /**
- * Artifacts to load into the servlet container's {@code lib} directory.
- */
- @Parameter
- private List<ProductArtifact> libArtifacts = new ArrayList<>();
- /**
- * Any plugins to be installed as bundled plugins.
- */
- @Parameter
- private List<ProductArtifact> bundledArtifacts = new ArrayList<>();
- /**
- * The version of Atlassian Shared Access Layer (SAL) artifacts to use.
- *
- * @deprecated Since 3.2, use {@link #pluginArtifacts} instead
- */
- @Deprecated
- @Parameter
- private String salVersion;
- /**
- * The version of the Atlassian Plugin Development Kit (PDK) to use.
- *
- * @deprecated Since 3.2, use {@link #pluginArtifacts} instead
- */
- @Deprecated
- @Parameter(defaultValue = DEFAULT_PDK_VERSION)
- private String pdkVersion;
- /**
- * The version of Atlassian REST artifacts to use.
- *
- * @deprecated Since 3.2, use {@link #pluginArtifacts} instead
- */
- @Deprecated
- @Parameter
- private String restVersion;
- /**
- * The Felix OSGi web console version.
- *
- * @deprecated Since 3.2, use {@code pluginArtifacts} instead
- */
- @Deprecated
- @Parameter(defaultValue = DEFAULT_WEB_CONSOLE_VERSION)
- private String webConsoleVersion;
- /**
- * The products' default DataSource, if any. DataSources can also be specified within each individual
- * {@code <product>} element.
- *
- * @since 8.3
- */
- @Parameter
- private DataSource dataSource;
- /**
- * The product nodes to start up. An empty list means single-node (non-clustered) operation.
- *
- * @since 8.3 before which we only ever started one node of each product
- */
- @Parameter
- private List<Node> nodes;
- // ---------------- end product context
- /**
- * Comma-delimited list of plugin artifacts in GROUP_ID:ARTIFACT_ID:VERSION form, where version can be
- * omitted, defaulting to LATEST.
- */
- @Parameter(property = "plugins")
- private String pluginArtifactsString;
- /**
- * Comma-delimited list of lib artifacts in GROUP_ID:ARTIFACT_ID:VERSION form, where version can be
- * omitted, defaulting to LATEST.
- */
- @Parameter(property = "lib.plugins")
- private String libArtifactsString;
- /**
- * Comma-delimited list of bundled plugin artifacts in GROUP_ID:ARTIFACT_ID:VERSION form, where version can be
- * omitted, defaulting to LATEST.
- */
- @Parameter(property = "bundled.plugins")
- private String bundledArtifactsString;
- /**
- * The project's build directory.
- */
- @Parameter(property = "project.build.directory", required = true)
- protected File targetDirectory;
- /**
- * The filename of the plugin's JAR file.
- */
- @Parameter(property = "project.build.finalName", required = true)
- protected String finalName;
- /**
- * If the plugin and optionally its test plugin should be installed
- */
- @Parameter(property = "install.plugin", defaultValue = "true")
- protected boolean installPlugin;
- /**
- * The local Maven repository. This is used by the artifact resolver to download resolved
- * JARs and put them in the local repository so that they won't have to be fetched again next
- * time the plugin is executed.
- */
- @Parameter(property = "localRepository")
- private ArtifactRepository localRepository;
- /**
- * The remote Maven repositories used by the artifact resolver to look for JARs.
- */
- @Parameter(property = "project.remoteArtifactRepositories")
- private List<ArtifactRepository> repositories;
- /**
- * The product configurations.
- */
- @Parameter
- private List<Product> products = new ArrayList<>();
- /**
- * A map of {instanceId -> Product}, initialized by {@link #createProductContexts()}.
- * Cannot be set by the user.
- */
- private Map<String, Product> productMap;
- /**
- * The file to which the container's log output will be sent.
- */
- @Parameter
- private String output;
- /**
- * Comma-delimited list of directories containing plugin resources. See the
- * {@code AlternativeDirectoryResourceLoader} class in the {@code atlassian-plugins} project for details.
- */
- @Parameter(property = "additional.resource.folders")
- private String additionalResourceFolders;
- /**
- * Start the products in parallel (TestGroups).
- */
- @Parameter(property = "parallel", defaultValue = "false")
- protected boolean parallel;
- /**
- * Whether to wait for full initialization of the product, e.g. for the plugin system to be up.
- */
- @Parameter(property = "await.full.initialization", defaultValue = "true")
- private boolean awaitFullInitialization;
- /**
- * A license to override any provided by the product data file.
- *
- * @since 8.2
- */
- @Parameter(property = "product.license")
- private String productLicense;
- // -------------------------------------- Methods -------------------------------------
- @Override
- public final void execute() throws MojoExecutionException, MojoFailureException {
- pluginArtifacts.addAll(toArtifacts(pluginArtifactsString));
- libArtifacts.addAll(toArtifacts(libArtifactsString));
- bundledArtifacts.addAll(toArtifacts(bundledArtifactsString));
- systemPropertyVariables.putAll((Map) systemProperties);
- doExecute();
- }
- protected abstract void doExecute() throws MojoExecutionException, MojoFailureException;
- // Returns a Product containing the properties of this Mojo, i.e. the top-level AMPS <configuration>
- private Product createDefaultProductContext() throws MojoExecutionException {
- final Product product = new Product();
- product.setId(getProductId());
- product.setCustomContainerArtifact(customContainerArtifact);
- product.setContainerId(containerId);
- product.setServer(server);
- product.setContextPath(contextPath);
- product.setJvmArgs(jvmArgs);
- product.setStartupTimeout(startupTimeout);
- product.setShutdownTimeout(shutdownTimeout);
- product.setNodes(nodes);
- // If they aren't defined, define those system properties. They will override the product
- // handler's properties.
- final Map<String, Object> properties = new HashMap<>(systemPropertyVariables);
- properties.put("atlassian.sdk.version", getAmpsPluginVersion());
- putDefaultedSystemProperty(properties, "atlassian.dev.mode", "true");
- putDefaultedSystemProperty(properties, "atlassian.allow.insecure.url.parameter.login", "true");
- putDefaultedSystemProperty(properties, "java.awt.headless", "true");
- putDefaultedSystemProperty(properties, "plugin.resource.directories", getResourceDirs());
- putDefaultedSystemProperty(properties, "plugin.root.directories", buildRootProperty());
- product.setSystemPropertyVariables(properties);
- product.setBundledArtifacts(bundledArtifacts);
- product.setLibArtifacts(libArtifacts);
- product.setApplications(applications);
- product.setPluginArtifacts(pluginArtifacts);
- product.setLog4jProperties(log4jProperties);
- product.setHttpPort(httpPort);
- product.setAjpPort(ajpPort);
- // HTTPS settings to pass via cargo to tomcat
- product.setUseHttps(useHttps);
- product.setHttpsPort(httpsPort);
- product.setHttpsClientAuth(httpsClientAuth);
- product.setHttpsSSLProtocol(httpsSslProtocol);
- product.setHttpsKeystoreFile(httpsKeystoreFile);
- product.setHttpsKeystorePass(httpsKeystorePass);
- product.setHttpsKeyAlias(httpsKeyAlias);
- product.setHttpsHttpSecure(httpsHttpSecure);
- product.setVersion(productVersion);
- product.setDataVersion(productDataVersion);
- product.setDataPath(productDataPath);
- product.setDataOverridesPath(productDataOverridesPath);
- product.setLicense(productLicense);
- // continue to have these work for now
- product.setRestVersion(restVersion);
- product.setSalVersion(salVersion);
- product.setAwaitFullInitialization(awaitFullInitialization);
- product.setDevToolboxVersion(devToolboxVersion);
- product.setEnableDevToolbox(enableDevToolbox);
- product.setEnablePde(enablePde);
- product.setEnablePluginViewer(enablePluginViewer);
- product.setEnableQuickReload(enableQuickReload);
- product.setPdeVersion(pdeVersion);
- product.setPdkVersion(pdkVersion);
- product.setPluginViewerVersion(pluginViewerVersion);
- product.setQuickReloadVersion(quickReloadVersion);
- product.setWebConsoleVersion(webConsoleVersion);
- if (dataSource != null) {
- product.setDataSources(singletonList(dataSource));
- }
- return product;
- }
- /**
- * Returns a comma-separated list of resource directories for on-the-fly reloading.
- * If a test plugin is detected, the test resource directories are included as well.
- *
- * @return see description
- */
- private String getResourceDirs() {
- final List<String> resourceDirs = new ArrayList<>();
- // Additional resource folders
- final String[] additionalResourceDirs = split(trimToEmpty(additionalResourceFolders), ",");
- for (final String resourceDir : additionalResourceDirs) {
- final File dir = new File(resourceDir);
- if (dir.exists()) {
- resourceDirs.add(trim(resourceDir));
- }
- }
- final MavenProject mavenProject = getMavenContext().getProject();
- // Project resource directories
- for (final Resource resource : mavenProject.getResources()) {
- final File resourceDir = new File(resource.getDirectory());
- if (resourceDir.exists()) {
- resourceDirs.add(resource.getDirectory());
- }
- }
- // Test resource directories
- if (shouldDeployTestJar(getMavenContext())) {
- for (final Resource resource : mavenProject.getTestResources()) {
- resourceDirs.add(resource.getDirectory());
- }
- }
- return join(",", resourceDirs);
- }
- /**
- * @return the path of the project root, for the <tt>plugin.root.directories</tt> system property.
- * @since 3.6
- */
- private String buildRootProperty() {
- return Optional.of(getMavenContext())
- .map(MavenContext::getProject)
- .map(MavenProject::getBasedir)
- .map(File::getPath)
- .orElse("");
- }
- /**
- * If the given map doesn't contain the given key, this method puts an entry for that key, where the value is the
- * value of that key as a system property, defaulted to the given value.
- *
- * @param map the map to populate
- * @param key the key to add if necessary
- * @param defaultValue the value to add if the system property with that key has no value
- */
- private static void putDefaultedSystemProperty(
- final Map<String, Object> map, final String key, final String defaultValue) {
- map.computeIfAbsent(key, k -> System.getProperty(k, defaultValue));
- }
- /**
- * Sets the default values of the given product.
- *
- * @param product the product whose default values are to be set
- */
- private void setDefaultValues(final Product product) {
- final ProductHandler handler = getProductHandler(product.getId());
- //Apply the common default values
- product.setDataVersion(System.getProperty("product.data.version", product.getDataVersion()));
- product.setVersion(System.getProperty("product.version", product.getVersion()));
- product.setDataPath(System.getProperty("product.data.path", product.getDataPath()));
- product.setInstanceId(getProductInstanceId(product));
- product.setArtifactRetriever(new ArtifactRetriever(
- artifactResolver, repositorySystem, localRepository, repositories, repositoryMetadataManager));
- if (containerIdNotDefinedOrProductSpecific(product)) {
- try {
- product.setContainerId(handler.getDefaultContainerId(product));
- } catch (MojoExecutionException e) {
- product.setContainerId(handler.getDefaultContainerId());
- }
- product.setContainerNotSpecified(true);
- }
- if (product.getServer() == null) {
- product.setServer(DEFAULT_SERVER);
- }
- if (product.getPdkVersion() == null) {
- product.setPdkVersion(DEFAULT_PDK_VERSION);
- }
- if (product.getWebConsoleVersion() == null) {
- product.setWebConsoleVersion(DEFAULT_WEB_CONSOLE_VERSION);
- }
- if (product.isEnableDevToolbox() == null) {
- product.setEnableDevToolbox(true);
- }
- if (product.getDevToolboxVersion() == null) {
- product.setDevToolboxVersion(DEFAULT_DEV_TOOLBOX_VERSION);
- }
- if (product.isEnableQuickReload() == null) {
- product.setEnableQuickReload(false);
- }
- if (product.getQuickReloadVersion() == null) {
- product.setQuickReloadVersion(DEFAULT_QUICK_RELOAD_VERSION);
- }
- if (product.isEnablePluginViewer() == null) {
- product.setEnablePluginViewer(false);
- }
- if (product.getPluginViewerVersion() == null) {
- product.setPluginViewerVersion(DEFAULT_PLUGIN_VIEWER_VERSION);
- }
- if (product.getPdeVersion() == null) {
- product.setPdeVersion(DEFAULT_PDE_VERSION);
- }
- if (product.getOutput() == null) {
- product.setOutput(output);
- }
- if (product.getStartupTimeout() <= 0) {
- product.setStartupTimeout(DEFAULT_PRODUCT_STARTUP_TIMEOUT);
- }
- if (product.getShutdownTimeout() <= 0) {
- product.setShutdownTimeout(DEFAULT_PRODUCT_SHUTDOWN_TIMEOUT);
- }
- if (product.getHttpPort() == 0) {
- product.setHttpPort(handler.getDefaultHttpPort());
- }
- if (product.getUseHttps() == null) {
- product.setUseHttps(false);
- }
- if (product.getHttpsPort() == 0) {
- product.setHttpsPort(handler.getDefaultHttpsPort());
- }
- if (product.getHttpsClientAuth() == null) {
- product.setHttpsClientAuth(DEFAULT_HTTPS_CLIENTAUTH);
- }
- if (product.getHttpsSSLProtocol() == null) {
- product.setHttpsSSLProtocol(DEFAULT_HTTPS_SSL_PROTOCOL);
- }
- if (product.getHttpsKeystoreFile() == null) {
- product.setHttpsKeystoreFile(DEFAULT_HTTPS_KEYSTOREFILE);
- }
- if (product.getHttpsKeystorePass() == null) {
- product.setHttpsKeystorePass(DEFAULT_HTTPS_KEYSTOREPASS);
- }
- if (product.getHttpsKeyAlias() == null) {
- product.setHttpsKeyAlias(DEFAULT_HTTPS_KEYALIAS);
- }
- if (product.getHttpsHttpSecure() == null) {
- product.setHttpsHttpSecure(Boolean.parseBoolean(DEFAULT_HTTP_SECURE));
- }
- if (product.getVersion() == null) {
- product.setVersion("RELEASE");
- }
- if (product.getDataVersion() == null) {
- // Default the productDataVersion to match the productVersion. Defaulting to LATEST
- // is bad because there is no guarantee that a snapshots let alone a more recent
- // version of a product's data is compatible with an earlier version of the product or
- // that a product is required to provide a 'downgrade' task. Developers can still
- // specify LATEST explicitly
- product.setDataVersion(product.getVersion());
- }
- if (product.getContextPath() == null) {
- product.setContextPath(handler.getDefaultContextPath());
- }
- if (product.getDataSources() == null) {
- product.setDataSources(new ArrayList<>());
- }
- product.initialiseNodes();
- }
- private static boolean containerIdNotDefinedOrProductSpecific(final Product product) {
- return product.getContainerId() == null || isProductSpecificContainerId(product);
- }
- private static boolean isProductSpecificContainerId(final Product product) {
- return "productSpecific".toUpperCase(ENGLISH).equals(product.getContainerId().toUpperCase(ENGLISH));
- }
- /**
- * Returns the plugins required by the {@code atlassian-plugins-osgi-testrunner} framework.
- *
- * @return an unmodifiable list
- */
- @Nonnull
- public final List<ProductArtifact> getTestFrameworkPlugins() {
- if (testFrameworkPlugins.isEmpty()) {
- // JUnit OSGi bundle
- final String jUnitVersion =
- getMavenContext().getVersionOverrides().getProperty(JUNIT_ARTIFACT_ID, JUNIT_VERSION);
- testFrameworkPlugins.add(new ProductArtifact(JUNIT_GROUP_ID, JUNIT_ARTIFACT_ID, jUnitVersion));
- // Test Runner Plugin
- testFrameworkPlugins.add(new ProductArtifact(
- TESTRUNNER_GROUP_ID, TESTRUNNER_BUNDLE_ARTIFACT_ID, getTestRunnerVersion()));
- }
- return unmodifiableList(testFrameworkPlugins);
- }
- /**
- * Returns the version of the Atlassian Plugins Test Runner Plugin to load. The version is derived as follows:
- * <ol>
- * <li>If the {@link MavenContext#getVersionOverrides()} specify a version, use that, otherwise</li>
- * <li>if the project has a dependency upon {@code com.atlassian.plugins:atlassian-plugins-osgi-testrunner},
- * which it may do in order to use {@link com.atlassian.plugins.osgi.test.AtlassianPluginsTestRunner}, then
- * use the version of that, otherwise</li>
- * <li>use version {@value #ATLASSIAN_TEST_RUNNER_VERSION}.</li>
- * </ol>
- *
- * @return a non-blank version
- * @see MavenContext#getVersionOverrides()
- */
- private String getTestRunnerVersion() {
- final MavenContext mavenContext = getMavenContext();
- final Properties overrides = mavenContext.getVersionOverrides();
- final Artifact testRunnerDependency =
- getReactorArtifact(mavenContext, TESTRUNNER_GROUP_ID, TESTRUNNER_ARTIFACT_ID);
- final String testRunnerVersion = Optional.ofNullable(testRunnerDependency)
- .map(Artifact::getVersion)
- .orElse(ATLASSIAN_TEST_RUNNER_VERSION);
- return overrides.getProperty(TESTRUNNER_BUNDLE_ARTIFACT_ID, testRunnerVersion);
- }
- /**
- * Builds the map {instanceId -> Product}, based on:
- * <ul>
- * <li>the {@literal <products>} tag</li>
- * <li>the configuration values inherited from the {@literal <configuration>} tag
- * </ul>
- *
- * @throws MojoExecutionException if something goes wrong
- */
- private Map<String, Product> createProductContexts() throws MojoExecutionException {
- final Map<String, Product> productContexts = new HashMap<>();
- // Products in the <products> tag inherit from the upper settings, e.g. when there's an <httpPort> tag for all products
- makeProductsInheritDefaultConfiguration(products, productContexts);
- productContexts.values().forEach(this::setDefaultValues);
- return productContexts;
- }
- /**
- * Returns the map { instanceId -> Product } with initialized values.
- */
- protected final Map<String, Product> getProductContexts() throws MojoExecutionException {
- if (productMap == null) {
- productMap = createProductContexts();
- }
- return productMap;
- }
- /**
- * Puts the list of {@literal <products>} in productMap:
- * <ul>
- * <li>The {@literal <product>} from the amps-maven-plugin configuration (if missing, RefApp is used)</li>
- * <li>The {@literal <products>} from the amps-maven-plugin configuration</li>
- * </ul>
- */
- @VisibleForTesting
- final void makeProductsInheritDefaultConfiguration(
- final List<Product> products, final Map<String, Product> productMap)
- throws MojoExecutionException {
- final Product defaultProduct = createDefaultProductContext();
- productMap.put(getProductId(), defaultProduct);
- for (final Product product : products) {
- final Product processedProduct = product.merge(defaultProduct);
- final String instanceId = getProductInstanceId(processedProduct);
- productMap.put(instanceId, processedProduct);
- }
- }
- private static String getProductInstanceId(final Product processedProduct) {
- return processedProduct.getInstanceId() == null ? processedProduct.getId() : processedProduct.getInstanceId();
- }
- /**
- * Attempts to stop the given products one by one, within the product-level timeout.
- */
- protected final void stopProducts(final Collection<Product> products) throws MojoExecutionException {
- final ExecutorService executor = newFixedThreadPool(products.size());
- try {
- final long before = System.nanoTime();
- final List<Product> reversed = new ArrayList<>(products);
- reverse(reversed);
- for (final Product product : reversed) {
- shutDown(product, executor);
- }
- final long after = System.nanoTime();
- getLog().info("amps:stop in " + NANOSECONDS.toSeconds(after - before) + "s");
- } catch (final InterruptedException e) {
- currentThread().interrupt();
- } catch (ExecutionException e) {
- throw new MojoExecutionException("Exception while stopping the products", e);
- }
- // If products were launched in parallel, check they are stopped: Cargo returns before products are down
- if (parallel) {
- waitForProducts(products, false);
- }
- }
- private void shutDown(final Product product, final ExecutorService executor)
- throws InterruptedException, ExecutionException {
- // Shut down the product, waiting no longer than product.getShutdownTimeout() milliseconds
- final Future<?> task = executor.submit(() -> {
- getLog().info(product.getInstanceId() + ": Shutting down");
- try {
- getProductHandler(product.getId()).stop(product);
- } catch (MojoExecutionException e) {
- getLog().error("Exception while trying to stop " + product.getInstanceId(), e);
- }
- });
- try {
- task.get(product.getShutdownTimeout(), MILLISECONDS);
- } catch (TimeoutException e) {
- getLog().info(product.getInstanceId() + " shutdown: Didn't return in time");
- task.cancel(true);
- }
- }
- /**
- * Waits until all products are running or stopped
- *
- * @param startingUp true if starting up the products, false if shutting down.
- */
- protected final void waitForProducts(final Collection<Product> products, final boolean startingUp)
- throws MojoExecutionException {
- for (final Product product : products) {
- for (final Node node : product.getNodes()) {
- awaitStateChange(product, node, startingUp, getLog());
- }
- }
- }
- /**
- * Applies this mojo's {@code parallel} configuration to the given products.
- *
- * @param products the products to mutate
- */
- protected final void setParallelMode(final Collection<Product> products) {
- products.forEach(product -> product.setSynchronicity(parallel));
- }
- }