lundi 29 avril 2013

La sérialisation XML avec XStream

XStream est une bibliothèque Java qui permet de transformer un grappe d'objet Java en flux XML et inversement.
Simple d'utilisation dans les cas standards, elle répond à presque tout les besoins.

Avec l'objet ci-dessous :
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Toto {
 public String toto = "1";
 public List titi = new ArrayList() ;
 public Date tata = new Date() ;
 
 public Toto() {
  titi.add("truc") ;
  titi.add("bidule") ; 
 }
}
Note, pour facilite la lecture et l'exemple, les attributs sont public.

Avec les lignes suivantes, un rendu XML est obtenu :
XStream stream = new XStream();
System.out.println(stream.toXML(new Toto())) ;

Voici le rendu :
<fr.ca.cat.Toto>
  <toto>1</toto>
  <titi>
    <string>truc</string>
    <string>bidule</string>
  </titi>
  <tata>2013-02-28 16:54:48.246 UTC</tata>
</fr.ca.cat.Toto>

Par défaut, les balises sont créées avec le nom du champs, ce qui dans certain cas peut ne pas correspondre.

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.

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.

lundi 8 avril 2013

Résoudre la version d'un artefact Maven avec Maven 3

Il peut être utile, dans le cadre d'un projet de résoudre la version d'un artefact lorsqu'une version générique est passée en paramètre (RELEASE, LATEST, x.x.x-SNAPSHOT).
Pour ce faire, il n'y a pas d'autre choix que de créer un plugin maison, pour enchaîner avec un traitement particularité.
Pour ce faire, il est nécessaire de se plonger dans la documentation volumineuse des API maven. De plus, l'API a évolué en version 3 (même si l'API v2 est toujours disponible).

Dans un premier temps, il faut créer le pom adéquat :
package org.test.maven.plugin;

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.ArtifactResolutionException;
import org.sonatype.aether.resolution.VersionRequest;
import org.sonatype.aether.resolution.VersionResolutionException;
import org.sonatype.aether.resolution.VersionResult;
import org.sonatype.aether.util.artifact.DefaultArtifact;

/**
 * Ce plugin affiche la version resolue d'un artefact
 * 
 * @goal version-artifact
 */
public class VersionArtefact extends AbstractMojo {
 /**
  * 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 {   
   VersionResult version = getVersionArtifact() ;
   
   getLog().info(version.toString());
  } catch (VersionResolutionException e) {
   throw new MojoExecutionException("Impossible de recuperer la version de l'artefact", e);
  }
 }
 
 /**
  * Renvoi le fichier correspondant à l'artefact.
  * Prend en charge le téléchargement dans le repo local.
  *
  * @return le fichier demandé
  * @throws ArtifactResolutionException en cas d'erreur lors de la recherche de l'artefact
  */
    private VersionResult getVersionArtifact() throws VersionResolutionException {
  DefaultArtifact artifact = new DefaultArtifact(groupId, artifactId,
    classifier, type, version);
  
        VersionRequest request = new VersionRequest(artifact, RepositoryUtils.toRepos(remoteRepos), null);
        VersionResult version = repoSystem.resolveVersion(repoSession, request) ; 
  
        return version;
    } 
}

Il est nécessaire de récupérer les repositories Maven et l'interface permettant de les piloter.
L'interface s’appelle Aether.
Ensuite, le système fonctionne avec un principe de requête et de réponse.
Une requête avec l'artifactId, groupId... est créé, l'interface est appelé est le résultat est récupéré.

Attention ! Si l'artefact n'existe pas et qu'une version générique est passée en paramètre, un exception est levé. Sinon, la version renvoyée est celle donnée en paramètre.
Il n'y a donc pas moyen de savoir si l'artefact existe. En réalité si, mais vous ne trouverez rien sur ce sujet sur internet.
Pour cela, rendez-vous la semaine prochaine pour connaitre l'astuce.

Voici alors le code (très simple) :
<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>org.test.maven.plugin</groupId>
    <artifactId>test-plugin-maven</artifactId>
    <packaging>maven-plugin</packaging>
    <version>1.0.0-SNAPSHOT</version>
 
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-plugin-plugin</artifactId>
    <version>3.0.4</version>
   </plugin>
  </plugins>
 </build>

 <dependencies> 
  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-aether-provider</artifactId>
   <version>3.0.4</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>org.apache.maven</groupId>
   <artifactId>maven-core</artifactId>
   <version>3.0.3</version>
   <scope>compile</scope>
  </dependency>
 </dependencies>

</project>

Ainsi, une version SNAPSHOT aura comme retour :
1.2.1-20121227.145212-1 @ nexus-libraries (http://xxxxxxx:8081/nxus/content/groups/public/, releases+snapshots)

lundi 1 avril 2013

Création d'un serveur en Java [2/2]

Dans l'article précédant, un rapide appeçu de comment créer un serveur en Java a été abordé.
Le principal inconvénient, c'est de ne pouvoir avoir qu'un client. Pas très pratique.

Il va donc être nécessaire de déléguer la réponse client à un thread.

Il y aura donc deux classes.
La première créer le serveur et écoute les connexions clientes.
La deuxième dialogue avec le client et est donc un thread.

La première classe :
package org.emeric.exemple.echo2;

import java.net.ServerSocket;


public class EchoServer {

    public static void main(String[] args) throws Exception {
        final ServerSocket socket = new ServerSocket(4444) ;
          
        while (true) {
            System.out.println("Waiting for client...");
            new EchoRequestHandler(socket.accept());
        }      
    }
}

La deuxième classe :
package org.emeric.exemple.echo2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * Class to read request
 * 
 * @author Emeric MARTINEAU
 */
public class EchoRequestHandler extends Thread implements Runnable  {
    /**
     * Socket of client
     */
    private Socket socket ;
    
    /**
     * Constructor
     * 
     * @param s socket
     */
    public EchoRequestHandler(final Socket s)
    {
        socket = s;
        Thread t = new Thread(this) ;
        t.setDaemon(true) ;
        t.start() ;
    }
    
    /**
     * Read and response to the client
     */
    @Override
    public void run()
    {
        System.out.println("New client...") ;
        
        try {
            // Reader
            final BufferedReader in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            
            // Auto flush, when println() call
            final PrintWriter out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())), true);        
        
            String str = null ;
            do {
                // Read and wait if no data
                str = in.readLine() ;
                // Print
                out.println(str) ;
            } while (str != null) ;
            
            out.close() ;
            
            socket.close() ;
        } catch (final IOException e) {
            // TODO
        }
        
        System.out.println("Bye client...");
    }
}

Vous voilà prêt à dévolloper de nombreux serveurs en Java.