All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.universalmediaserver.external.AbstractExternalDependencyMojo Maven / Gradle / Ivy

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 **/

package com.universalmediaserver.external;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.installer.ArtifactInstallationException;
import org.apache.maven.artifact.installer.ArtifactInstaller;
import org.apache.maven.artifact.manager.WagonConfigurationException;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.install.AbstractInstallMojo;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.building.DefaultSettingsBuilder;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuilder;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsBuildingRequest;
import org.apache.maven.settings.io.DefaultSettingsReader;
import org.apache.maven.settings.io.DefaultSettingsWriter;
import org.apache.maven.settings.validation.DefaultSettingsValidator;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.apache.maven.wagon.UnsupportedProtocolException;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.authentication.AuthenticationException;
import org.apache.maven.wagon.authorization.AuthorizationException;
import org.apache.maven.wagon.observers.Debug;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.apache.maven.wagon.repository.Repository;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.archiver.util.DefaultFileSet;
import org.codehaus.plexus.digest.Digester;
import org.codehaus.plexus.digest.DigesterException;
import org.codehaus.plexus.digest.Md5Digester;
import org.codehaus.plexus.digest.Sha1Digester;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.WriterFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Base class for all goals in this plugin.
 *
 * @threadSafe
 */
public abstract class AbstractExternalDependencyMojo extends AbstractInstallMojo {

	/**
	 * Used to look up Artifacts in the remote repository.
	 *
	 * @component
	 */
	protected RepositorySystem repositorySystem;

	/**
	 * Collection of ArtifactItems to work on. (ArtifactItem contains groupId,
	 * artifactId, version, type, classifier, location, destFile, markerFile and
	 * overwrite.) See "Usage" and "Javadoc" for details.
	 *
	 * @parameter
	 * @required
	 */
	protected ArrayList artifactItems;

	/**
	 * Used to look up Artifacts in the remote repository.
	 *
	 * @component
	 */
	protected ArtifactResolver artifactResolver;

	/**
	 * Used to install Artifact in the local repository.
	 *
	 * @component
	 */
    protected ArtifactInstaller installer;

	/**
	 * List of Remote Repositories used by the resolver
	 *
	 * @parameter default-value="${project.remoteArtifactRepositories}"
	 * @readonly
	 */
	protected List remoteRepositories;

	/**
	 * Maven WagonManager
	 *
	 * @component role="org.apache.maven.artifact.manager.WagonManager"
	 * @required
	 * @readonly
	 */
	protected WagonManager wagonManager;

	/**
	 * Maven ArchieverManager.
	 *
	 * @component
	 * @readonly
	 */
	protected ArchiverManager archiverManager;

	/**
	 * Maven project
	 *
	 * @parameter default-value="${project}"
	 * @required
	 * @readonly
	 */
	protected MavenProject project;

	/**
	 * Path to user settings.xml
	 *
	 * @parameter default-value="${user.home}/.m2/settings.xml"
	 * @required
	 */
	protected String userSettings;

	/**
	 * Path to global settings.xml
	 *
	 * @parameter default-value="${env.M2_HOME}/conf/settings.xml"
	 * @required
	 */
	protected String globalSettings;

	/**
	 * Maven local repository
	 *
	 * @parameter default-value="${localRepository}"
	 * @required
	 * @readonly
	 */
	protected ArtifactRepository localRepository;

	/**
	 * Staging directory for external dependencies
	 *
	 * @parameter default-value="${project.build.directory}/external-dependencies"
	 */
	protected String stagingDirectory;

	/**
	 * Forces a download, maven install, maven deploy
	 *
	 * @parameter default-value="false"
	 */
	protected boolean force;

	/**
	 * If this property is set to true, the downloaded file's checksum will be
	 * verified with a query against Maven Central Repository to make sure the
	 * artifact isn't already there.
	 *
	 * @parameter default-value="false"
	 */
	protected boolean centralChecksumVerification;

	/**
	 * Flag that indicates whether to create checksums (MD5, SHA-1) or not.
	 *
	 * @parameter property="createChecksum" default-value="true"
	 * @required
	 */
	protected boolean createChecksum;

	/**
	 * Flag that indicates whether to disable Java's SSL certificate and host validation.
	 *
	 * @parameter property="disableSSLValidation" default-value="false"
	 */
	protected boolean disableSSLValidation;

	/**
	 * Newline constant
	 */
	protected final String NEWLINE = System.getProperty("line.separator");

	@Override
	public void execute() throws MojoExecutionException, MojoFailureException {
		// Super class lack a default value and requires it to be set manually
		super.localRepository = this.localRepository;

		if (disableSSLValidation) {
			try {
				SSLContext sslContext = SSLContext.getInstance("SSL");
			    sslContext.init(null, new TrustManager[] { new GullableTrustManager() }, new SecureRandom());
			    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
			    HttpsURLConnection.setDefaultHostnameVerifier(new GullableHostnameVerifier());
			} catch (NoSuchAlgorithmException | KeyManagementException e) {
				getLog().warn("Disabling of SSL verification failed: " + e.getMessage());
				getLog().debug(e);
			}
		}
	}

	/**
	 * Create Maven Artifact object from ArtifactItem configuration descriptor.
	 *
	 * @param item the item
	 * @return Artifact
	 */
	protected Artifact createArtifact(ArtifactItem item) {
		Artifact artifact = null;

		// create Maven artifact with a classifier
		artifact = repositorySystem.createArtifactWithClassifier(item.getGroupId(), item.getArtifactId(),
			item.getVersion(), item.getPackaging(), item.getClassifier());

		return artifact;
	}

	/**
	 * Generates a (temporary) POM file from the plugin configuration. It's the
	 * responsibility of the caller to delete the generated file when no longer
	 * needed.
	 *
	 * @param artifact the artifact
	 * @return The path to the generated POM file, never null.
	 * @throws MojoExecutionException             If the POM file could not be generated.
	 */
	protected File generatePomFile(ArtifactItem artifact) throws MojoExecutionException {
		Model model = generateModel(artifact);

		Writer writer = null;
		try {
			File pomFile = File.createTempFile(artifact.getGroupId() + "." + artifact.getArtifactId(), ".pom");

			writer = WriterFactory.newXmlWriter(pomFile);
			new MavenXpp3Writer().write(writer, model);

			return pomFile;
		} catch (IOException e) {
			throw new MojoExecutionException("Error writing temporary POM file: " + e.getMessage(), e);
		} finally {
			IOUtil.close(writer);
		}
	}

	/**
	 * Generates a minimal model from the user-supplied artifact information.
	 *
	 * @param artifact the artifact
	 * @return The generated model, never null.
	 */
	protected Model generateModel(ArtifactItem artifact) {
		Model model = new Model();
		model.setModelVersion("4.0.0");
		model.setGroupId(artifact.getGroupId());
		model.setArtifactId(artifact.getArtifactId());
		model.setVersion(artifact.getVersion());
		model.setPackaging(artifact.getPackaging());

		return model;
	}

	/**
	 * Resolves the file path and returns a file object instance for an artifact
	 * item.
	 *
	 * @param artifactItem the artifact item
	 * @return File object for artifact item
	 */
	protected File getFullyQualifiedArtifactFilePath(ArtifactItem artifactItem) {
		String artifactStagingDirectory = artifactItem.getStagingDirectory();
		if (artifactStagingDirectory == null || artifactStagingDirectory.isEmpty()) {
			artifactStagingDirectory = stagingDirectory;
		}
		return new File(artifactStagingDirectory, artifactItem.getLocalFile());
	}

	/**
	 * Verifies a checksum for the specified file.
	 *
	 * @param targetFile the path to the file from which the checksum is
	 * verified, must not be null.
	 * @param digester the checksum algorithm to use, must not be null.
	 * @param checksum the checksum to verify.
	 * @return The result
	 * @throws MojoExecutionException
	 *             If the checksum could not be installed.
	 */
	protected boolean verifyChecksum(File targetFile, Digester digester, String checksum) throws MojoExecutionException {
		getLog().debug("Calculating " + digester.getAlgorithm() + " checksum for " + targetFile);
		try {
			String calculatedChecksum = digester.calc(targetFile);
			getLog().debug("Generated checksum : " + calculatedChecksum);
			getLog().debug("Expected checksum  : " + checksum);
			return calculatedChecksum.equals(checksum);
		} catch (DigesterException e) {
			throw new MojoExecutionException("Failed to calculate " + digester.getAlgorithm() + " checksum for "
				+ targetFile, e);
		}
	}

	/**
	 * Validate artifact configured checksum against specified file.
	 *
	 * @param artifactItem to validate checksum against
	 * @param targetFile to validate checksum against
	 * @throws MojoExecutionException the mojo execution exception
	 * @throws MojoFailureException the mojo failure exception
	 */
	protected void verifyArtifactItemChecksum(ArtifactItem artifactItem, File targetFile) throws MojoExecutionException, MojoFailureException {

		// If a checksum was specified, we must verify the checksum against the downloaded file
		if (artifactItem.hasChecksum()) {
			getLog().info(String.format(
				"Verifying checksum on downloaded file %s: %s",
				targetFile.getName(),
				artifactItem.getChecksum()
			));

			// Perform SHA1 checksum verification
			getLog().debug("Testing for SHA1 checksum on artifact " + artifactItem.toString());
			if (!verifyChecksum(targetFile, new Sha1Digester(), artifactItem.getChecksum())) {
				getLog().debug("Verification failed on SHA1 checksum for file: " + targetFile.getAbsolutePath());
				getLog().debug("Testing for MD5 checksum on artifact: " + artifactItem.toString());

				// Did not pass MD5 checksum verification, now test SHA1 checksum
				if (!verifyChecksum(targetFile, new Md5Digester(), artifactItem.getChecksum())) {
					// Checksum verification failed, throw error
					throw new MojoFailureException(
						"Both SHA1 and MD5 checksum verification failed for: " + NEWLINE +
						"  groupId    : " + artifactItem.getGroupId() + NEWLINE +
						"  artifactId : " + artifactItem.getArtifactId() + NEWLINE +
						"  version    : " + artifactItem.getVersion() + NEWLINE +
						"  checksum   : " + artifactItem.getChecksum() + NEWLINE +
						"  file       : " + targetFile.getAbsolutePath()
					);
				} else {
					getLog().info("Verification passed on MD5 checksum for artifact: " + artifactItem.toString());
				}
			} else {
				getLog().info("Verification passed on SHA1 checksum for artifact: " + artifactItem.toString());
			}
		}
	}

	/**
	 * Validate artifact configured extracted file checksum against specified
	 * file.
	 *
	 * @param artifactItem to validate checksum against
	 * @param targetFile to validate checksum against
	 * @throws MojoExecutionException MojoExecutionException
	 * @throws MojoFailureException MojoFailureException
	 */
	protected void verifyArtifactItemExtractFileChecksum(ArtifactItem artifactItem, File targetFile) throws MojoExecutionException, MojoFailureException {

		// If a checksum was specified, we must verify the checksum against the extracted file
		if (artifactItem.hasExtractFileChecksum()) {
			getLog().info(String.format(
				"Verifying checksum on extracted file %s: %s",
				targetFile.getName(),
				artifactItem.getExtractFileChecksum()
			));

			// Perform SHA1 checksum verification
			getLog().debug("Testing for SHA1 checksum on artifact: " + artifactItem.toString());
			if (!verifyChecksum(targetFile, new Sha1Digester(), artifactItem.getExtractFileChecksum())) {
				getLog().debug("Verification failed on SHA1 checksum for extracted file: " + targetFile.getAbsolutePath());
				getLog().info("Testing for MD5 checksum on artifact: " + artifactItem.toString());

				// Did not pass SHA1 checksum verification, now test MD5 checksum
				if (!verifyChecksum(targetFile, new Md5Digester(), artifactItem.getExtractFileChecksum())) {
					// checksum verification failed, throw error
					throw new MojoFailureException(
						"Both MD5 and SHA1 checksum verification failed for: " + NEWLINE +
						"  groupId        : " + artifactItem.getGroupId() + NEWLINE +
						"  artifactId     : " + artifactItem.getArtifactId() + NEWLINE +
						"  version        : " + artifactItem.getVersion() + NEWLINE +
						"  checksum       : " + artifactItem.getExtractFileChecksum() + NEWLINE +
						"  extracted file : " + targetFile.getAbsolutePath());
				} else {
					getLog().info("Verification passed on MD5 checksum for artifact: " + artifactItem.toString());
				}
			} else {
				getLog().info("Verification passed on SHA1 checksum for artifact: " + artifactItem.toString());
			}
		}
	}

	/**
	 * Gets the text content of a named attribute from a Node
	 * or null if it doesn't exist.
	 * @param node the node to search
	 * @return The text content of the node or null
	 */

	private String getAttribute(Node node, String attributeName) {
		Node attributeNode = node.getAttributes().getNamedItem(attributeName);
		if (attributeNode != null) {
			return attributeNode.getTextContent();
		}
		else return null;
	}

	/**
	 * Checks if a named attribute exists for a give Node.
	 * @param node the node to search
	 * @return The result
	 */
	private boolean hasAttribute(Node node, String attributeName) {
		return getAttribute(node, attributeName) != null;
	}

	/**
	 * Validate downloaded file artifact checksum does not match another
	 * artifact's checksum that already exists in the central Maven repository.
	 * Using the search.maven.org REST API to perform a checksum lookup.
	 *
	 * @since 0.1
	 *
	 * @param artifactItem to validate checksum against
	 * @param targetFile to validate checksum against
	 * @throws MojoExecutionException MojoExecutionException
	 * @throws MojoFailureException MojoFailureException
	 */
	protected void verifyArtifactItemChecksumByCentralLookup(ArtifactItem artifactItem, File targetFile)
		throws MojoExecutionException, MojoFailureException {
		// Skip this artifact checksum verification?
		if (centralChecksumVerification == false && artifactItem.getCentralChecksumVerification() == false) {
			return;
		}

		boolean artifactMismatch = false;
		StringBuilder detectedArtifacts = new StringBuilder();

		// Calculate SHA1 checksum
		digester.calculate(targetFile);
		String sha1Checksum = digester.getSha1();
		getLog().debug("Performing Central Repository lookup on artifact SHA1 checksum: " + sha1Checksum);

		// perform REST query against Central Repository checksum lookup API
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		try {
			builder = dbf.newDocumentBuilder();
		} catch (ParserConfigurationException e1) {
			getLog().error("Could not create XML Document parser: " + e1.getMessage());
			getLog().info("Skipping Central Repository checksum verification");
			getLog().debug(e1);
			return;
		}
		Document document;
		try {
			document = builder.parse(String.format("http://search.maven.org/solrsearch/select?q=1:\"%s\"&rows=20&wt=xml", sha1Checksum));
		} catch (SAXException e) {
			getLog().error("Could not parse Central Repository response: " + e.getMessage());
			getLog().info("Skipping Central Repository checksum verification");
			getLog().debug(e);
			return;
		} catch (IOException e) {
			getLog().error("Could not contact Central Repository: " + e.getMessage());
			getLog().info("Skipping Central Repository checksum verification");
			getLog().debug(e);
			return;
		}
		NodeList artifactList = document.getElementsByTagName("doc");

		// were any results returned?
		if (artifactList != null && artifactList.getLength() > 0) {

			int nodeCount = 0;
			NodeList resultNodes = document.getElementsByTagName("result");
			int resultNodesLength = resultNodes.getLength();
			for (int i = 0; i < resultNodesLength; i++) {
				Node node = resultNodes.item(i);
				if (
					hasAttribute(node, "name") && hasAttribute(node, "numFound") &&
					getAttribute(node, "name").equalsIgnoreCase("response")
				) {
					try {
						nodeCount = Integer.parseInt(getAttribute(node, "numFound"));
						break;
					} catch (NumberFormatException e) {
						nodeCount = 0;
					}
				}
			}
			// If we can't interpret the results, use the list length (although it might be truncated)
			if (nodeCount == 0) {
				nodeCount = artifactList.getLength();
			}

			getLog().info(
				nodeCount + " existing artifacts found in Central Repository checksum lookup, verifying artifact GAV");

			/*
			 * Iterate over all the query returned artifact definitions and
			 * attempt to determine if any of the returned artifact GAV do
			 * no match the GAV of the attempted install artifact.
			 */
			int artifactListLength = artifactList.getLength();
			for (int index = 0; index < artifactListLength; index++) {
				Node artifactNode = artifactList.item(index);
				if (artifactNode.hasChildNodes()) {
					NodeList children = artifactNode.getChildNodes();
					for (int loop = 0; loop < children.getLength(); loop++) {
						Node artifactProperty = children.item(loop);

						// We only inspect the strings with "name" attribute
						if (!artifactProperty.getNodeName().equals("str") || !hasAttribute(artifactProperty, "name")) {
							continue;
						}

						String propertyName = getAttribute(artifactProperty, "name");
						// Append returned artifact property names to an output message string
						detectedArtifacts.append(
							"       " + propertyName + " : " + artifactProperty.getTextContent() + NEWLINE
						);

						if (propertyName.equalsIgnoreCase("a")) {
							/*
							 * Attempt to validate the returned artifact's
							 * ArtifactId against the target install artifact
							 */
							if (!artifactProperty.getTextContent().equalsIgnoreCase(artifactItem.getArtifactId())) {
								getLog().error(
									"Artifact id found in Central Repository lookup does not match: " +
									artifactProperty.getTextContent() + " != " + artifactItem.getArtifactId());
								artifactMismatch = true;
							}
						} else if (propertyName.equalsIgnoreCase("g")) {
							/*
							 * Attempt to validate the returned artifact's
							 * GroupId against the target install artifact
							 */
							if (!artifactProperty.getTextContent().equalsIgnoreCase(artifactItem.getGroupId())) {
								getLog().error(
									"Artifact group id found in Central Repository lookup does not match: " +
									 artifactProperty.getTextContent() + " != " + artifactItem.getGroupId());
								artifactMismatch = true;
							}
						} else if (
							propertyName.equalsIgnoreCase("v") &&
							!artifactProperty.getTextContent().equalsIgnoreCase(artifactItem.getVersion())
						) {
							/*
							 * Attempt to validate the returned artifact's
							 * Version against the target install artifact
							 */
							getLog().error(
								"Artifact version found in Central Repository lookup does not match: " +
								artifactProperty.getTextContent() + " != " + artifactItem.getVersion());
							artifactMismatch = true;
						}
					}
				}

				detectedArtifacts.append(NEWLINE);
			}
		} else {
			getLog().info(
				"No existing artifact found in Central Repository checksum lookup, continuing artifact installation");
		}

		// Was a mismatch detected?
		if (artifactMismatch == true) {
			// Checksum verification failed, throw error
			throw new MojoFailureException(
				"Central Repository artifact checksum verification failed on artifact defined in POM:" + NEWLINE + NEWLINE +
				"       groupId    : " + artifactItem.getGroupId() + NEWLINE +
				"       artifactId : " + artifactItem.getArtifactId() + NEWLINE +
				"       version    : " + artifactItem.getVersion() + NEWLINE +
				"       checksum   : " + sha1Checksum + NEWLINE +
				"       file       : " + targetFile.getAbsolutePath() + NEWLINE + NEWLINE +
				"The following artifact(s) were detected using the same checksum:" + NEWLINE +
				detectedArtifacts.toString() + NEWLINE +
				"Please verify that the GAV defined on the target artifact is correct." + NEWLINE
			);
		}
	}

	/**
	 * Generates a default settings builder.
	 * @return
	 * 			The SettingsBuilder instance
	 */
	public SettingsBuilder getSettingsBuilder() {
		DefaultSettingsBuilder settingsBuilder = new DefaultSettingsBuilder();
		settingsBuilder.setSettingsReader(new DefaultSettingsReader());
		settingsBuilder.setSettingsValidator(new DefaultSettingsValidator());
		settingsBuilder.setSettingsWriter(new DefaultSettingsWriter());
		return settingsBuilder;
	}

	/**
	 * Generates a settings builder request from parameters.
	 * @return
	 * 			The SettingsBuilderRequest instance
	 */
	public SettingsBuildingRequest getSettingsBuildingRequest() {
		DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
		if (userSettings != null) {
			request.setUserSettingsFile(new File(userSettings));
		}
		if (globalSettings != null) {
			request.setGlobalSettingsFile(new File(globalSettings));
		}
		return request;
	}

	/**
	 * resolve the artifact in local or remote repository
	 *
	 * @param artifact the artifact to resolve
	 * @return
	 * 			Whether or not the artifact was resolved
	 */
	protected boolean resolveArtifactItem(Artifact artifact) {
		// Determine if the artifact is already installed in an existing Maven repository
		ArtifactResolutionRequest request = new ArtifactResolutionRequest();
		request.setArtifact(artifact);
		request.setRemoteRepositories(remoteRepositories);
		request.setLocalRepository(localRepository);
		return artifactResolver.resolve(request).isSuccess();
	}

	/**
	 * Download an artifact.
	 *
	 * @param artifactItem the artifact item
	 * @param artifact the artifact
	 * @param artifactFile the artifact file
	 * @param cachedDownloads the cached downloads
	 * @throws MojoExecutionException the mojo execution exception
	 * @throws MojoFailureException the mojo failure exception
	 */
	protected void downloadArtifact(final ArtifactItem artifactItem, Artifact artifact, File artifactFile, Map cachedDownloads) throws MojoExecutionException, MojoFailureException {

		if (artifactItem.getDownloadUrl() != null) {
			URL downloadUrl;
			try {
				downloadUrl = new URL(artifactItem.getDownloadUrl());
			} catch (MalformedURLException e1) {
				throw new MojoExecutionException("Could not interpret URL " + artifactItem.getDownloadUrl(), e1);
			}

			final File tempDownloadFile;

			if (cachedDownloads.containsKey(downloadUrl)) {
				tempDownloadFile = cachedDownloads.get(downloadUrl);
				getLog().info(String.format("Artifact %s is already downloaded from URL", artifactItem.getDownloadUrl()));
				getLog().debug("Using cached download: " + tempDownloadFile.getAbsolutePath());
			} else {
				// create a temporary download file
				try {
					tempDownloadFile = File.createTempFile(artifactItem.getLocalFile(), "." + getExtension(downloadUrl));
				} catch (IOException e) {
					throw new MojoExecutionException("Could not create temporary file", e);
				}

				getLog().info(
					String.format("Downloading artifact %s from URL %s", artifactItem.toString(),
					artifactItem.getDownloadUrl()
				));
				getLog().debug("Downloading artifact to temporary file: " + tempDownloadFile.getAbsolutePath());

				String endPointUrl = downloadUrl.getProtocol() + "://" + downloadUrl.getAuthority();
				Repository repository = new Repository("additonal-configs", endPointUrl);
				Wagon wagon;
				try {
					wagon = wagonManager.getWagon(repository);
				} catch (WagonConfigurationException | UnsupportedProtocolException e) {
					throw new MojoExecutionException(String.format(
						"Could not initialize protocol \"%s\": %s",
						downloadUrl.getProtocol(),
						e.getMessage()
					), e);
				}
				if (getLog().isDebugEnabled()) {
					Debug debug = new Debug();
					wagon.addSessionListener(debug);
					wagon.addTransferListener(debug);
				}
				wagon.setTimeout(artifactItem.getTimeout());

				ProxyInfo proxyInfo = getProxyInfo();

				try {
					if (proxyInfo != null) {
						wagon.connect(repository, wagonManager.getAuthenticationInfo(repository.getId()), proxyInfo);
					} else {
						wagon.connect(repository, wagonManager.getAuthenticationInfo(repository.getId()));
					}

					wagon.get(downloadUrl.getPath().substring(1), tempDownloadFile);
				} catch (ConnectionException | TransferFailedException | ResourceDoesNotExistException | AuthorizationException | AuthenticationException e) {
					throw new MojoExecutionException(
						"Failed to download artifact " + artifactItem.toString() + ": " + e.getMessage(), e
					);
				}

				getLog().debug("Caching temporary file for later: " + tempDownloadFile);
				cachedDownloads.put(downloadUrl, tempDownloadFile);
			}

			/*
			 * Verify file checksum (if a checksum was defined).
			 * MojoFailureException exception will be thrown if
			 * verification fails.
			 *
			 * Note: In theory, there might be conflicting checksums
			 * configured for the same artifact; checksum
			 * verification may thus be done several times for a
			 * cached download.
			 */
			verifyArtifactItemChecksum(artifactItem, tempDownloadFile);

			/*
			 * If this artifact is not configured to extract a file,
			 * then simply copy the downloaded file to the target
			 * artifact file.
			 */

			if (!artifactItem.hasExtractFile()) {
				getLog().info(
					"Copying downloaded artifact file to staging path: " + artifactFile.getAbsolutePath()
				);
				try {
					FileUtils.copyFile(tempDownloadFile, artifactFile);
				} catch (IOException e) {
					throw new MojoExecutionException(
						"Failed to copy artifact " + artifactItem.toString() + " to staging path \"" +
						artifactFile.getAbsolutePath() + "\": " + e.getMessage(),
						e
					);
				}
			} else {
				/*
				 * If this artifact is configured to extract a file,
				 * then extract the file from the downloaded compressed
				 * file to the target artifact file
				 */
				getLog().info(
					"Extracting target file from downloaded compressed file: " + artifactItem.getExtractFile()
				);

				File tempOutputDir = FileUtils.createTempFile(tempDownloadFile.getName(), ".dir", null);
				if (!tempOutputDir.mkdirs()) {
					throw new MojoExecutionException("Could not create temporary folder: " + tempOutputDir.getAbsolutePath());
				}
				File extractedFile = new File(tempOutputDir, artifactItem.getExtractFile());

				UnArchiver unarchiver;
				try {
					unarchiver = archiverManager.getUnArchiver(tempDownloadFile);
				} catch (NoSuchArchiverException e) {
					if (tempDownloadFile.getName().endsWith(".gz")) {
						try {
							unarchiver = archiverManager.getUnArchiver("gzip");
						} catch (NoSuchArchiverException e1) {
							throw new MojoExecutionException(
								"No gzip unarchiver available for: " + tempDownloadFile.getAbsolutePath(), e
							);
						}
						unarchiver.setDestFile(extractedFile);
					} else
						throw new MojoExecutionException(
							"No unarchiver available for archive type: " + tempDownloadFile.getAbsolutePath(), e
						);
				}

				// Ensure the path exists to write the file to
				File parentDirectory = artifactFile.getParentFile();
				if (parentDirectory != null && !parentDirectory.exists() && !artifactFile.getParentFile().mkdirs()) {
					throw new MojoExecutionException("Could not create folder: " + artifactFile.getParentFile().getAbsolutePath());
				}

				unarchiver.setSourceFile(tempDownloadFile);
				if (unarchiver.getDestFile() == null)
					unarchiver.setDestDirectory(tempOutputDir);
				unarchiver.extract();

				// If an archive entry was not found, then throw a Mojo exception
				if (extractedFile.isFile()) {
					try {
						FileUtils.copyFile(extractedFile, artifactFile);
					} catch (IOException e) {
						throw new MojoExecutionException(
							"Failed to copy \"" + extractedFile.getAbsolutePath() +
							"\" to \"" + artifactFile.getAbsolutePath() + "\": " +
							e.getMessage(), e
						);
					}
				} else if (extractedFile.isDirectory() && artifactItem.isRepack()) {
					Archiver archiver;
					try {
						archiver = archiverManager.getArchiver(artifactFile);
					} catch (NoSuchArchiverException e) {
						throw new MojoExecutionException(
							"No unarchiver available for archive type: " + artifactFile.getAbsolutePath(), e
						);
					}
					archiver.setDestFile(artifactFile);
					archiver.addFileSet(new DefaultFileSet(extractedFile));
					try {
						archiver.createArchive();
					} catch (ArchiverException | IOException e) {
						throw new MojoExecutionException(
							"Failed to create archive \"" + artifactFile.getAbsolutePath() + "\": " + e.getMessage(),
							e
						);
					}
				} else {
					// Extraction failed, throw error
					throw new MojoExecutionException(
						"Could not find target artifact file to extract from downloaded resource:" + NEWLINE +
						"  groupId      : " + artifact.getGroupId() + NEWLINE +
						"  artifactId   : " + artifact.getArtifactId() + NEWLINE +
						"  version      : " + artifact.getVersion() + NEWLINE +
						"  extractFile  : " + artifactItem.getExtractFile() + NEWLINE +
						"  download URL : " + artifactItem.getDownloadUrl()
					);
				}

				getLog().info("Extracted target file to staging path: " + artifactFile.getAbsolutePath());
			}

			// Update the artifact items local file property
			try {
				artifactItem.setLocalFile(artifactFile.getCanonicalPath());
			} catch (IOException e) {
				throw new MojoExecutionException(
					"Failed to get canonical path for \"" + artifactFile.getAbsolutePath() + "\": " + e.getMessage(),
					e
				);
			}

		} else {
			throw new MojoExecutionException("Download URL for " + artifactItem.toString() + "must be specified");
		}
	}

	/**
	 * Gets the file extension.
	 *
	 * @param downloadURL the download url
	 * @return the extension
	 */
	protected String getExtension(URL downloadURL) {
		String path = downloadURL.getPath();
		if (path.endsWith(".tar.gz")) {
			return "tar.gz";
		}
		if (path.endsWith(".tar.bz2")) {
			return "tar.bz2";
		}
		return FileUtils.getExtension(path);
	}

	/**
	 * Looks up ProxyInfo from Maven settings.
	 *
	 * @return ProxyInfo
	 */
	protected ProxyInfo getProxyInfo() {
		ProxyInfo proxyInfo = null;
		try {
			Settings settings = getSettingsBuilder().build(getSettingsBuildingRequest()).getEffectiveSettings();

			if (settings != null && settings.getActiveProxy() != null) {
				Proxy settingsProxy = settings.getActiveProxy();
				proxyInfo = new ProxyInfo();
				proxyInfo.setHost(settingsProxy.getHost());
				proxyInfo.setType(settingsProxy.getProtocol());
				proxyInfo.setPort(settingsProxy.getPort());
				proxyInfo.setNonProxyHosts(settingsProxy.getNonProxyHosts());
				proxyInfo.setUserName(settingsProxy.getUsername());
				proxyInfo.setPassword(settingsProxy.getPassword());
			}
		} catch (SettingsBuildingException e) {
			getLog().warn("Could not read Maven settings, skipping proxy configuration: " + e.getMessage());
			getLog().debug(e);
			return null;
		}
		return proxyInfo;
	}

	/**
	 * Verify artifact.
	 *
	 * @param artifactItem the artifact item
	 * @param stagedArtifactFile the staged artifact file
	 * @throws MojoExecutionException the mojo execution exception
	 * @throws MojoFailureException the mojo failure exception
	 */
	protected void verifyArtifact(ArtifactItem artifactItem, File stagedArtifactFile) throws MojoExecutionException, MojoFailureException {

		if (artifactItem.hasExtractFile()) {
			/*
			 * If this artifact is configured to extract a file,
			 * then the checksum verification will need to take
			 * place if there is a separate extract file checksum
			 * property defined
			 */
			if (artifactItem.hasExtractFileChecksum()) {
				/*
				 * Verify extracted file checksum (if an extract
				 * file checksum was defined). MojoFailureException
				 * exception will be thrown if verification fails
				 */
				verifyArtifactItemExtractFileChecksum(artifactItem, stagedArtifactFile);
			}
		} else {
			/*
			 * If this is not a packed file, then verify the
			 * downloaded file using the regular checksum property
			 *
			 * Verify file checksum (if a checksum was defined).
			 * MojoFailureException exception will be thrown if
			 * verification fails
			 */
			verifyArtifactItemChecksum(artifactItem, stagedArtifactFile);
		}

		/*
		 * perform search.maven.org REST query to ensure that this
		 * artifacts checksum is not resolved to an existing
		 * artifact already hosted in another Maven repository
		 */
		verifyArtifactItemChecksumByCentralLookup(artifactItem, stagedArtifactFile);
	}

	/**
	 * Install an artifact into the local repository
	 *
	 * @param artifactItem the current ArtifactItem
	 * @param artifact the Artifact representing the ArtifactItem
	 * @param stagedArtifactFile the File representing the staged
	 * location for the ArtifactItem
	 * @throws MojoExecutionException MojoExecutionException
	 */
	protected void installArtifact(ArtifactItem artifactItem, Artifact artifact, File stagedArtifactFile) throws MojoExecutionException {

		// Create Maven artifact POM file
		File generatedPomFile = null;

		// Don't generate a POM file for POM artifacts
		if (!"pom".equals(artifactItem.getPackaging())) {
			if (artifactItem.getPomFile() != null) {
				/*
				 * If a POM file was provided for the artifact
				 * item, then use that POM file instead of
				 * generating a new one
				 */
				ProjectArtifactMetadata pomMetadata = new ProjectArtifactMetadata(artifact, artifactItem.getPomFile());
				getLog().debug("Installing defined POM file: " + artifactItem.getPomFile());
				artifact.addMetadata(pomMetadata);
			} else {
				// Dynamically create a new POM file for this artifact
				generatedPomFile = generatePomFile(artifactItem);
				ProjectArtifactMetadata pomMetadata = new ProjectArtifactMetadata(artifact, generatedPomFile);

				if (artifactItem.getGeneratePom() == true) {
					getLog().debug(
						"installing generated POM file: " + generatedPomFile.getAbsolutePath());
					artifact.addMetadata(pomMetadata);
				}
			}
		}

		// Install artifact to local repository
		try {
			installer.install(stagedArtifactFile, artifact, localRepository);
		} catch (ArtifactInstallationException e) {
			throw new MojoExecutionException(
				"Could not install artifact " + artifact.toString() + " to local repository: " + e.getMessage(), e
			);
		}

		// Install checksum files to local repository
		boolean createChecksum;
		if (artifactItem.getCreateChecksum() != null) {
			createChecksum = artifactItem.getCreateChecksum();
		} else {
			createChecksum = this.createChecksum;
		}
		installChecksums(artifact, createChecksum);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy