lundi 22 avril 2013

Vérifier qu'un artifact maven existe v2

Dans le post précédent, un première solution a été donnée pour savoir si un artifact existe ou nom.
Le problème, c'est que cette vérification se base sur le pom.xml, or il est possible d'avoir un pom sans jar par exemple.

Le nouvel exemple, va être plus restrictif.
Il va indiquer si un artifact est présent sur un repository distant. Il peut être très facilement adapté pour supporter le repository local (il y a une log dans le code pour ce cas).

Le code ne supporte que les versions release (1.2.0), les versions SNPASHOT, RELEASE, LASTEST ne sont pas supportées.
Il faudra au préalable résoudre la version.

Le principe est donc :
  • récupérer le descriptor,
  • regarder s'il y a un repository,
  • s'il y a un repository, construire un requête HTTP et lire le status (réponse).

voici 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 distant pour une version RELEASE uniquement
 * 
 * @goal check-exists-artifact
 */
public class VerifierArtefactExistant2 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() ;
            
            boolean exists = checkIfRemoteFileExists(artefactFile) ;
            
            if (!exists)
            {
                // 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.
                //
                // Attention, dans le cas d'un artifact present uniquement en local, il ne 
                // faut pas le supprimer
                if (artefactFile.getRepository() == null)
                {
                    getLog().debug("Suppression des informations dans le repository local") ;
                    cleanArtifactLocalRepositoryData(artefactFile) ;
                }
            }
        } 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() ;
        }
    }    
    
    /**
     * Verifie qu'une version release existe bien sur le serveur.
     * NE FONCTIONNE PAS POUR version = 'SNAPSHOT', 'LASTEST', 'RELEASE'
     * Il faudra resoudre la version d'abord.
     * 
     * @param artefactFile
     * @return
     */
    private boolean checkIfRemoteFileExists(final ArtifactDescriptorResult artefactFile)
    {
        boolean fileExits = false ;
        
        org.sonatype.aether.repository.ArtifactRepository repository = artefactFile.getRepository() ;
        
        if (repository != null)
        {        
            ArtifactRepository selectedRepository = rechercherRemoteRepository(repository) ;
                        
            if (selectedRepository == null)
            {
                // La variable repository est un repository local
                // Cela veut dire que l'artifact n'existe pas a distance, mais seulement en local,
                // c'est une erreur !
                getLog().warn("L'artifact est present en local mais pas sur le serveur depot distant !") ;
            }
            else
            {
                fileExits = verifierExistanceArtifactDistant(artefactFile, selectedRepository) ;
            }

        }
        
        return fileExits ;
    }
    
    /**
     * Recherche le repository distant dont l'ID correspond a celui en entree
     * 
     * @param repository repository Aether
     * 
     * @return repository maven
     */
    private ArtifactRepository rechercherRemoteRepository(org.sonatype.aether.repository.ArtifactRepository repository)
    {
        ArtifactRepository selectedRepository = null ;
        
        // Recherche le repository distant d'ou le l'artifact a ete recuperer
        for(ArtifactRepository currentRepository : remoteRepos)
        {
            if (repository.getId().equals(currentRepository.getId()))
            {
                selectedRepository = currentRepository ;
            }
        }
        
        return selectedRepository ;
    }
    
    /**
     * Verifie que dans le repository distant, la matiere existe bien.
     * 
     * @param artefactFile artifact
     * @param remoteRepository repository disant
     * @return
     */
    private boolean verifierExistanceArtifactDistant(ArtifactDescriptorResult artefactFile, ArtifactRepository remoteRepository)
    {
        boolean remoteFileExits = false ;
        
        Artifact artifact = artefactFile.getArtifact() ;
        
        // Creer le nom du fichier avec les informations
        String fileName ;
        
        if (StringUtils.isBlank(artifact.getClassifier()))
        {
            fileName = String.format("%s-%s.%s", artifact.getArtifactId(), artifact.getVersion(), artifact.getExtension()) ;
        }
        else
        {
            fileName = String.format("%s-%s-%s.%s", artifact.getArtifactId(), artifact.getVersion(), artifact.getClassifier(), artifact.getExtension()) ;
        }            
        
        // Construit l'URL
        String url = String.format("%s%s/%s/%s/%s", remoteRepository.getUrl(), artifact.getGroupId().replace(".", "/"),
                artifact.getArtifactId(), artifact.getVersion(), fileName) ;
        
        // Ouvre une connexion vers le fichier
        try {
            getLog().info(String.format("Verification de l'existance de l'artifact '%s'", url)) ;
            
            URL u = new URL(url) ;

            HttpURLConnection http = (HttpURLConnection) u.openConnection() ;
            int status = http.getResponseCode() ;

            if (status >= 200 && status < 300)
            {
                remoteFileExits = true;
                getLog().info("Artifact trouve") ;
            }
            else
            {
                getLog().warn("Les informations de description (pom.xml) de l'artifact est present sur le serveur depot distant, "
                        + "mais l'artifact est introuvable sur ce serveur !") ;
            }
            
            http.disconnect() ;
        } catch (MalformedURLException e) {
            getLog().error(
                    String.format("Probleme de creation de l'url '%s'", url), e) ;
        } catch (IOException e) {
            getLog().error(
                    String.format("Impossible d'ouvrir une connexion reseau vers '%s'", url), e) ;
        }        
        
        return remoteFileExits ;
    }    
}

Le code commence à devenir conséquent, mais il répond bien à la problématique.

Aucun commentaire:

Enregistrer un commentaire