lundi 15 avril 2013

Vérifier qu'un artifact maven existe

Précédemment, un exemple de récupération de version d'un artifact maven a été présenté.
Maintenant, une demande qui n'est pas nouvelle est "comment savoir si un artifact existe sur le repository local ou distant ?".
En cherchant sur internet, il faut bien avouer que les seules réponses trouvées sont :
  • tenter de télécharger l'artifact (http://stackoverflow.com/questions/4809238/maven-how-to-check-if-an-artifact-exists),
  • faire une requête HTTP sur un serveur type Nexus (http://www.jarradmbattaglia.com/2012/02/08/maven-how-to-check-if-an-artifact-in-nexus-using-http/)

Rien de satisfaisant, surtout si le but est de savoir si l'artifact existe sans télécharger l'artifact en question.

Le principe est le même que l'exemple précédent pour connaitre la version. Mais, l'astuce va être récupérer le descriptor. Et ensuite ?
Est-ce comme pour la résolution de version, si l'artifact n'existe pas, il n'y a pas d'erreur levée, ou un paramètre indiquant une erreur ?

La réponse est oui mais !
Lorsque les informations sur le descriptor est récupéré, il est possible de savoir sur quel repository il a été récupéré.
De sorte, que si il n'y a pas de repository indiqué, cela signifie que l'artifact n'a pas été trouvé !

Toutefois, ce n'est pas encore fini.
En effet, si l'artefact n'existe pas, une entrée est quand même créé dans le repository local et dans ce cas, s'il s'agit d'une version release, et qu'elle existe ensuite, maven n'essaiera pas de un re-téléchargement, car il note que la version n'existe pas.
Il faut alors supprimer le répertoire du repository local mais seulement à l'arrêt de la JVM car maven verrouille le répertoire.

Voici alors le code :
package org.test.maven.plugin;

import java.io.File;
import java.util.List;

import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.resolution.ArtifactDescriptorException;
import org.sonatype.aether.resolution.ArtifactDescriptorRequest;
import org.sonatype.aether.resolution.ArtifactDescriptorResult;
import org.sonatype.aether.util.artifact.DefaultArtifact;

/**
 * Ce plugin indique si l'artefact existe dans un repository (local ou distant)
 * 
 * @goal check-exists-artifact
 */
public class VerifierArtefactExistant extends AbstractMojo {
    /**
     * @parameter default-value="${localRepository}" 
     */
    private ArtifactRepository localRepository;    
    
    /**
     * The entry point to Aether, i.e. the component doing all the work.
     * 
     * @component
     */
    private RepositorySystem repoSystem;

    /**
     * The current repository/network configuration of Maven.
     * 
     * @parameter default-value="${repositorySystemSession}"
     * @readonly
     */
    private RepositorySystemSession repoSession;

    /**
     * List of Remote Repositories used by the resolver
     * 
     * @parameter expression="${project.remoteArtifactRepositories}"
     * @readonly
     * @required
     */
    protected List<ArtifactRepository> remoteRepos;

    /**
     * Group Id of Artifact 
     * 
     * @parameter default-value="${project.groupId}"
     * @required
     */
    private String groupId;

    /**
     * Name of Artifact
     * 
     * @parameter default-value="${project.artifactId}"
     * @required
     */
    private String artifactId;

    /**
     * Version of Artifact
     * 
     * @parameter default-value="${project.version}"
     */
    private String version;

    /**
     * Type of Artifact (War,Jar,etc)
     * 
     * @parameter default-value="${project.packaging}"
     * @required
     */
    private String type;

    /**
     * Classifier for Artifact (tests,sources,etc)
     * 
     * @parameter default-value="${project.classifier}"
     */
    private String classifier;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            ArtifactDescriptorResult artefactFile = getDescriptor() ;
            
            if (artefactFile.getRepository() == null)
            {                                
                getLog().error("Artifact inexistant") ;    
                
                // Si l'artefact n'existe pas, il faut supprimer le repertoire car maven
                // 'note' le fait qu'il n'a pas trouve et pour une version RELEASE, il ne
                // tentera pas un nouveau telechargement
                cleanArtifactLocalRepositoryData(artefactFile) ;
            }            
            else
            {
                getLog().info("Artefect trouve");
            }
        } catch (ArtifactDescriptorException e) {
            throw new MojoExecutionException("Impossible de recuperer les metadata de l'artefact", e);
        }
    }

    /**
     * Renvoi le descriptor de l'artefact.
     * 
     * @return le descriptor
     * @throws ArtifactDescriptorException
     *             en cas d'erreur lors de la recherche de l'artefact
     */
    private ArtifactDescriptorResult getDescriptor() throws ArtifactDescriptorException {
        DefaultArtifact artifact = new DefaultArtifact(groupId, artifactId,
                classifier, type, version);
        
        ArtifactDescriptorRequest request = new ArtifactDescriptorRequest(artifact,
                RepositoryUtils.toRepos(remoteRepos), null) ;
        ArtifactDescriptorResult descriptor = repoSystem.readArtifactDescriptor(repoSession, request) ;        

        return descriptor ;
    }
    
    /**
     * Suppression du repertoire
     * 
     * @param result resultat de la recherche de l'artefact descriptor
     */
    private void cleanArtifactLocalRepositoryData(ArtifactDescriptorResult result)
    {
        // Le chemin d'acces au repository local + construction du chemin vers 
        // les données
        final File dirToClean = new File(localRepository.getBasedir(),
                String.format("%s/%s/%s",
                        result.getArtifact().getGroupId().replace(".", "/"),
                        result.getArtifact().getArtifactId(),
                        result.getArtifact().getVersion())) ;
        
        if (!dirToClean.exists()) {
            getLog().warn(
                    String.format("Le repertoire '%s' n'existe pas.",
                            dirToClean.getAbsolutePath())) ;
        } else {
            if (getLog().isDebugEnabled())
            {
                getLog().debug(
                        String.format("Suppression du repertoire '%s'.",
                                dirToClean.getAbsolutePath())) ;                    
            }
            
            deleteDirectoryOnExit(dirToClean) ;
        }
    }
    
    /**
     * Supprime un repertoire et son contenu au shutdown de la VM car maven lock les fichiers.
     * 
     * @param directory repertoire a supprimer
     */
    private void deleteDirectoryOnExit(File directory)
    {
        if (directory.exists())
        {
            File[] listFile = directory.listFiles() ;
            
            for(File currentFile : listFile)
            {
                if (currentFile.exists())
                {
                    currentFile.deleteOnExit() ;
                }
            }
            
            directory.deleteOnExit() ;
        }
    }    
}

Le pom qui lance le goal :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>test.truc</groupId>
    <artifactId>kiki</artifactId>
    <version>1.2.1</version>
    <packaging>jar</packaging>
    <name>test-maven</name>

    <build>
        <plugins>
            <plugin>
                <groupId>rg.test.maven.plugin</groupId>
                <artifactId>maven-test-plugin</artifactId>
                <version>1.0.0-SNAPSHOT</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>check-exists-artifact</goal>
                        </goals>
                        <configuration>
                            <groupId>fr.truc.bidule</groupId>
                            <artifactId>coco</artifactId>
                            <version>1.0.11</version>
                            <type>jar</type>

                            <propertyResult>totoVariable</propertyResult>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>Hello world! ${totoVariable}</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>


Une réflexion vient à l'esprit, le contrôle se fait sur le pom.xml, mais il est possible que celui-ci soit présent, sans pour autant que le jar par exemple, exite lui.
La solution sera donné la prochaine fois.

Aucun commentaire:

Enregistrer un commentaire