3

How do I check from within a Mojo if an artifact already exists in the local repository?

I'm installing large binaries into the local Maven repository and I need to know if they already exist before attempting to download them.

Gili
  • 86,244
  • 97
  • 390
  • 689

3 Answers3

6

Solved with the help of http://docs.codehaus.org/display/MAVENUSER/Mojo+Developer+Cookbook

/**
 * The local maven repository.
 *
 * @parameter expression="${localRepository}"
 * @required
 * @readonly
 */
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private ArtifactRepository localRepository;
/**
 * @parameter default-value="${project.remoteArtifactRepositories}"
 * @required
 * @readonly
 */
private List<?> remoteRepositories;
/**
 * Resolves Artifacts in the local repository.
 * 
 * @component
 */
private ArtifactResolver artifactResolver;
/**
 * @component
 */
private ArtifactFactory artifactFactory;
[...]
Artifact artifact = artifactFactory.createArtifactWithClassifier(groupId, artifactId, version, packagingType, classifier);
boolean artifactExists;
try
{
  // Downloads the remote artifact, if necessary
  artifactResolver.resolve(artifact, remoteRepositories, localRepository);
  artifactExists = true;
}
catch (ArtifactResolutionException e)
{
  throw new MojoExecutionException("", e);
}
catch (ArtifactNotFoundException e)
{
  artifactExists = false;
}
if (artifactExists)
  System.out.println("Artifact found at: " + artifact.getFile());

If you want to check if a remote artifact exists without downloading it, you can use the Aether library to do the following (based on http://dev.eclipse.org/mhonarc/lists/aether-users/msg00127.html):

MavenDefaultLayout defaultLayout = new MavenDefaultLayout();
RemoteRepository centralRepository = new RemoteRepository.Builder("central", "default", "http://repo1.maven.org/maven2/").build();
URI centralUri = URI.create(centralRepository.getUrl());
URI artifactUri = centralUri.resolve(defaultLayout.getPath(artifact));
HttpURLConnection connection = (HttpURLConnection) artifactUri.toURL().openConnection();
connection.setRequestMethod("HEAD");
connection.connect();
boolean artifactExists = connection.getResponseCode() != 404;

With following dependency: org.eclipse.aether:aether-util:0.9.0.M2 and following imports:

import java.net.HttpURLConnection;
import java.net.URI;

import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.util.repository.layout.MavenDefaultLayout;
Jmini
  • 9,189
  • 2
  • 55
  • 77
Gili
  • 86,244
  • 97
  • 390
  • 689
  • I'm leaving this answer up in case anyone wants to look up an artifact without actually downloading it. – Gili Jan 27 '11 at 17:35
  • The part about this that I don't like, is the fact that you're actually not only trying, but in fact you are downloading the artifact. I doubt that's what you'd like to do with large artifacts. Have a look at my answer. – carlspring Jul 05 '13 at 16:21
  • @carlspring, you're right. Resolving an artifact causes it to get downloaded. – Gili Jul 06 '13 at 01:26
  • @carlspring, I've updated the answer with an explanation of how to check whether an artifact exists without downloading it. – Gili Jul 09 '13 at 20:49
  • I would recommend trying to inject the `Wagon` into your mojo and then the example I showed below. But your code should also do it. Just... not the Maven way, but... yeah, it should work. – carlspring Jul 09 '13 at 21:38
1

Since the answer which is accepted as correct, is no longer pointing to valid URL-s and because I know a better way, I am posting a new answer.

There's the wagon-maven-plugin, which has an exist goal. The documentation is a bit inaccurate, but you can use that.

Code-wise, you can have a look at the DefaultWagonDownload class' exists method:

/**
 * 
 * @param wagon - a Wagon instance
 * @param resource - Remote resource to check
 * @throws WagonException
 */
public boolean exists( Wagon wagon, String resource )
    throws WagonException
{
    return wagon.resourceExists( resource );
}
carlspring
  • 31,231
  • 29
  • 115
  • 197
  • I fixed the broken link in the accepted answer. As for this answer, it's not clear what I would pass as `resource`. How would I go from a `groupId:artifactId:classifier:version` to using this API? – Gili Jul 06 '13 at 01:26
  • The resource would be a URL to the respective artifact, of course. You would need to have a method that takes in an `Artifact` and an `ArtifactRepository` and return a URL. – carlspring Jul 06 '13 at 14:41
  • And for clarity GAV actually is ordered like `groupId:artifactId:version:type:classifier`. – carlspring Jul 06 '13 at 18:09
1

If you expect your artifacts being present in a remote maven repository, I'd suggest you simply use the copy mojo of the maven-dependency-plugin.

It will use normal maven resolution mechanism for retrieving artifacts so will not download something that is already in the local repository.

In a plugin, when using maven 2 (not sure about maven3) you can use the mojo executor to call a mojo from within you code easily.

Gili
  • 86,244
  • 97
  • 390
  • 689
SaM
  • 2,410
  • 1
  • 19
  • 19