IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

Inclure des DAO automatiquement dans les servlets par des beans [Framework]


Sujet :

Spring Java

  1. #1
    Invité
    Invité(e)
    Par défaut Inclure des DAO automatiquement dans les servlets par des beans
    Bonjour,

    Je bloque depuis quelques jours sur un des concepts de base de Spring. Je suis un nouvel utilisateur, qui doit effectuer un projet avec ce framework, et je m'avoue un peu perdu.

    J'ai crée des classes Métiers grâce à la génération automatique disponible dans Netbeans. Voici par exemple une classe Compte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    package horens.domain.models.auth;
     
    import java.io.Serializable;
    import java.util.Date;
    import javax.persistence.Basic;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.NamedQueries;
    import javax.persistence.NamedQuery;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    import javax.xml.bind.annotation.XmlRootElement;
     
    @Entity
    @Table(name = "auth_compte")
    @XmlRootElement
    @NamedQueries({
        @NamedQuery(name = "AuthCompte.findAll", query = "SELECT a FROM Compte a"),
        @NamedQuery(name = "AuthCompte.findByLogin", query = "SELECT a FROM Compte a WHERE a.login = :login"),
        @NamedQuery(name = "AuthCompte.findByPassword", query = "SELECT a FROM Compte a WHERE a.password = :password"),
        @NamedQuery(name = "AuthCompte.findByEmail", query = "SELECT a FROM Compte a WHERE a.email = :email"),
        @NamedQuery(name = "AuthCompte.findByNom", query = "SELECT a FROM Compte a WHERE a.nom = :nom"),
        @NamedQuery(name = "AuthCompte.findByPrenom", query = "SELECT a FROM Compte a WHERE a.prenom = :prenom"),
        @NamedQuery(name = "AuthCompte.findByDerniereConnexion", query = "SELECT a FROM Compte a WHERE a.derniereConnexion = :derniereConnexion")})
    public class Compte implements Serializable {
        private static final long serialVersionUID = 1L;
        @Id
        @Basic(optional = false)
        @Column(name = "login")
        private String login;
        @Basic(optional = false)
        @Column(name = "password")
        private String password;
        @Basic(optional = false)
        @Column(name = "email")
        private String email;
        @Basic(optional = false)
        @Column(name = "nom")
        private String nom;
        @Basic(optional = false)
        @Column(name = "prenom")
        private String prenom;
        @Column(name = "derniereConnexion")
        @Temporal(TemporalType.DATE)
        private Date derniereConnexion;
        @JoinColumn(name = "typeProfil", referencedColumnName = "idProfil")
        @ManyToOne(optional = false)
        private Profil typeProfil;
     
        public Compte() {
        }
     
        public Compte(String login) {
            this.login = login;
        }
     
        public Compte(String login, String password, String email, String nom, String prenom) {
            this.login = login;
            this.password = password;
            this.email = email;
            this.nom = nom;
            this.prenom = prenom;
        }
     
        public String getLogin() {
            return login;
        }
     
        public void setLogin(String login) {
            this.login = login;
        }
     
        public String getPassword() {
            return password;
        }
     
        public void setPassword(String password) {
            this.password = password;
        }
     
        public String getEmail() {
            return email;
        }
     
        public void setEmail(String email) {
            this.email = email;
        }
     
        public String getNom() {
            return nom;
        }
     
        public void setNom(String nom) {
            this.nom = nom;
        }
     
        public String getPrenom() {
            return prenom;
        }
     
        public void setPrenom(String prenom) {
            this.prenom = prenom;
        }
     
        public Date getDerniereConnexion() {
            return derniereConnexion;
        }
     
        public void setDerniereConnexion(Date derniereConnexion) {
            this.derniereConnexion = derniereConnexion;
        }
     
        public Profil getTypeProfil() {
            return typeProfil;
        }
     
        public void setTypeProfil(Profil typeProfil) {
            this.typeProfil = typeProfil;
        }
     
        @Override
        public int hashCode() {
            int hash = 0;
            hash += (login != null ? login.hashCode() : 0);
            return hash;
        }
     
        @Override
        public boolean equals(Object object) {
            if (!(object instanceof Compte)) {
                return false;
            }
            Compte other = (Compte) object;
            if ((this.login == null && other.login != null) || (this.login != null && !this.login.equals(other.login))) {
                return false;
            }
            return true;
        }
     
        @Override
        public String toString() {
            return "horens.domain.models.AuthCompte[ login=" + login + " ]";
        }
     
    }
    Ensuite, j'ai crée une classe DAO, qui permet de spécifier pour toutes ses classes filles la dataSource et le jdbcTemplate :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package horens.domain.dao;
     
    import javax.sql.DataSource;
    import org.hibernate.SessionFactory;
    import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
    import org.springframework.orm.hibernate3.HibernateTemplate;
     
     
    public abstract class DAO<T> {
     
            protected DataSource dataSource;
            protected SimpleJdbcTemplate jdbcTpl;
            private HibernateTemplate hibernateTemplate;
     
            public void setDataSource(DataSource dataSource) {
                this.dataSource = dataSource;
                jdbcTpl = new SimpleJdbcTemplate(dataSource);
            }
     
            public void setSessionFactory(SessionFactory sessionFactory) {   
                this.hibernateTemplate = new HibernateTemplate(sessionFactory);   
            }   
     
            public abstract boolean create(T obj);
     
            public abstract boolean delete(T obj);
     
            public abstract boolean update(T obj);
     
            public abstract T get(int id);
    }
    Enfin, pour terminer mon exemple, voilà la classe DAO, associé à la classe Compte donnée plus haut :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    package horens.domain.dao.auth;
     
    import horens.domain.dao.DAO;
    import horens.domain.models.auth.Compte;
    import java.io.Serializable;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Collection;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.stereotype.Service;
     
    public class CompteDAO extends DAO<Compte> implements Serializable {
     
     
        public Collection getAll() {
            return jdbcTpl.query("SELECT * FROM auth_compte", new CompteMapper());
        }
     
        @Override
        public boolean create(Compte obj) {
            jdbcTpl.update("INSERT INTO auth_compte(login, password, email, typeProfil, nom, prenom) VALUES(?,?,?,?,?,?)", 
                    obj.getLogin(), obj.getPassword(),
                    obj.getEmail(), obj.getTypeProfil(),
                    obj.getNom(), obj.getPrenom()
                    );
            return true;
        }
     
        @Override
        public boolean delete(Compte obj) {
            jdbcTpl.update("DELETE FROM auth_compte WHERE login = ?", 
                    obj.getLogin());
            return true;
        }
     
        @Override
        public boolean update(Compte obj) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
     
        @Override
        public Compte get(int id) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
     
        public Compte get(String login) {
            return (Compte) this.jdbcTpl.queryForObject(
                "SELECT * FROM auth_compte WHERE login = ?", 
                new CompteMapper(), login);
        }
     
     
        private static final class CompteMapper implements RowMapper {
     
            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                return new Compte(rs.getString("login"), 
                        rs.getString("password"), 
                        rs.getString("email"),
                        rs.getString("nom"),
                        rs.getString("prenom")
                        );
            }
        }
    }
    Toutes ces classes compilent. Je souhaite désormais pouvoir appeler la classe DAO facilement depuis une servlet. Et c'est là que le problème survient. J'ai suivi sur le net plusieurs manuels, docs et tutos... Chaque auteur avait sa version, et ça m'a plus embrouillé qu'autre chose. Au final, dans mon applicationContext.xml, en plus du dataSource et du sessionFactory j'ai ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <bean id="daoBase" class="horens.models.dao.DAO" abstract="true">
                <property name="sessionFactory" ref="sessionFactory" />
            </bean>
     
            <bean id="compteDao" class="horens.domain.dao.auth.CompteDAO" parent="daoBase"/>
    Or quand j'essayes d'appeler compteDao dans une servlet, ça en marche pas (NullPointerException quand je visite la page). Voici le code de ma servlet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    package horens.servlets.consultation;
     
    import horens.domain.dao.auth.CompteDAO;
    import horens.domain.models.auth.Compte;
    import java.io.IOException;
    import java.sql.SQLException;
    import java.util.Collection;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.WebApplicationContextUtils;
     
     
    @WebServlet(name = "VueCompteServlet", urlPatterns={"/VueCompteServlet"})
    public class VueCompteServlet extends HttpServlet {
     
        @Autowired
        private CompteDAO compteDAO;
     
        public void setCompteDAO(CompteDAO compteDAO) {
            this.compteDAO = compteDAO;
        }
     
        public CompteDAO getCompteDAO() { return this.compteDAO; }
     
        /** 
         * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // Ref dans l'url
            String login = request.getParameter("login");
     
            // Récupération d'un compte
            Compte cpt    = compteDAO.get(login);
     
            request.setAttribute("cpt", cpt);
            request.getRequestDispatcher("WEB-INF/jsp/compte/vueDetaillee.jsp").forward(request, response);
        }
     
        // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
        /** 
         * Handles the HTTP <code>GET</code> method.
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
     
        /** 
         * Handles the HTTP <code>POST</code> method.
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
     
        /** 
         * Returns a short description of the servlet.
         * @return a String containing servlet description
         */
        @Override
        public String getServletInfo() {
            return "Short description";
        }// </editor-fold>
    }

    ... et je ne comprends pas pourquoi. Pouvez-vous me donner quelques pistes ? Comment agit l'annotation @Autowired ?
    J'ai vu dans de nombreux tutos la déclaration d'une couche "Service", qui, à mon impression, reprend en grande partie les actions faites par le DAO. A quoi sert cette couche ?


    Merci d'avance, et bonnes fêtes.
    Dernière modification par mlny84 ; 01/12/2012 à 20h19. Motif: Conversion du préfixe

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    En général ce genre de problème est dû au fait que

    soit les classes en question ne sont pas scannées par Spring :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <context:component-scan base-package="…" />
    de l'applicationContext.xml n'est pas correct ou manque,

    soit les classes ne sont pas annotées correctement par les annotations @Controller, @Service, @Component, …
    (vérifiez que @WebServlet soit dans liste…)

    soit les conventions de programmation par "interface" sont mal utilisées

    soit il y a des ambiguïtés dans la résolution de classes implémentant l'interface visée par @Autowired (mais çà ne semble pas votre cas puisque vous n'utilisez pas la convention "par interface" …)

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Merci pour cette réponse rapide J'ai essayé 2 des 3 méthodes cités, puisque en effet, je ne travaille pas avec des interfaces, trouvant ceci trop lourd à mon goût (j'ai 19 classes DAO + 19 classes Objets métiers déjà à gérer...)
    Bref.

    Tout d'abord j'ai ajouté ceci dans mon applicationContext.xml :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <context:component-scan base-package="horens">
        <context:include-filter type="annotation" expression="horens.domain.dao.auth.CompteDAO" />
    </context:component-scan>
    Ceci n'a pas résolu le problème. J'ai donc décidé d'ajouter les annotations sur mes classes. Sur ma servlet, j'ai apposé @Controller, au dessus de @Webservlet, comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    @Controller
    @WebServlet(name = "VueCompteServlet", urlPatterns={"/VueCompteServlet"})
    public class VueCompteServlet extends HttpServlet {
    et dans CompteDAO, j'ai ajouté l'annotation @Service :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @Service
    public class CompteDAO extends DAO<Compte> implements Serializable {
    Cependant même erreur. J'ai fouillé dans la doc pour voir si c'était bien les bonnes annotations, et des recherches supplémentaires ne m'ont toujours rien donné. Je me sens un peu dans l'impasse la...
    Voyez-vous un autre point qui cloche ?

    Bonne journée.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    141
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 141
    Points : 178
    Points
    178
    Par défaut
    Bonjour comme l'as dit ssx3max je ne suis pas sûre de l'annotation juste parce que je ne l'a connais pas.
    Le problème vient de ta servlet, elle n'est surement pas déclarée dans le context c'est normal que tu as un Je te conseil de faire ceci.
    Dans ta classe CompteDAO créer une variable static que tu appel instance par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private static DAO<Compte> instance;
    private CompteDao(){
        instance = this;
    }
    public static DAO<Compte> getInstance(){
       synchronized (instance) {
    	return instance;
       }
    }
    Ce qui te permet de récupérer l'unique instance de ta Dao démarée dans le context Spring(tu peux améliorer la méthode getInstance pour que ca fasse un très bon singleton...)
    Dans ta servlet n'utilises pas l'annotation Autowired, il ne marchera pas, car elle n'est pas un bean Spring, mais plutot
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private final  DAO<Compte> compteDAO=CompteDAO.getInstance();
    pire avec l'utilisation de l'annotation @Controller tu fera n'importe quoi, HttpServlet ne répond pas aux attentes de Spring, le mélange va faire du n'importe quoi dans ton code.
    Sinon à la place de HttpServlet pourquoi tu n'utilises pas implémentation du Controller Spring ou étendre un de ces controller par défaut et retourner un ModelAndView ou un String comme ça tu ferras fonctionner ton annotation @Autowired tranquillement.
    Autre chose, l'annotation @Service est reservée pour les classes services, pour une Dao utilise plutot l'annotation @Repository...

  5. #5
    Invité
    Invité(e)
    Par défaut
    Oui, pas bête tout ça ! Je ne sais pas si faire des singletons est la méthode idéale, mais ça marche parfaitement, et ça produit quelque chose de pas trop sale dans les servlets.

    Merci beaucoup ray_fab.

  6. #6
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    Citation Envoyé par ray_fab Voir le message
    Autre chose, l'annotation @Service est reservée pour les classes services, pour une Dao utilise plutot l'annotation @Repository...
    @Component, @Service, @Repository sont des archétypes, ici en ordre croissant de spécialisation, et s'il y a bien une raison d'utiliser @Repository pour la couche DAO ce n'est pas parce @Service est "réservé" aux "services" (un DAO est une forme de service…)
    mais parce qu'en utilisant @Repository, les exceptions levées par les accès de bas niveau à la base de données sont automatiquement traduites :
    la couche supérieure n'a alors qu'à s'occuper de gérer les exceptions Spring DataAccessException au lieu de tout l'éco-système des exceptions spécifiques à la sous-cache d'accès.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    141
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 141
    Points : 178
    Points
    178
    Par défaut
    http://JeitEmgie ok pour ce que tu dis mais quand on fait les choses bien, tous les problèmes d'ordres transversaux sont délégués aux services et l'accès à la base de données aux Dao, dans ce cas l'annotation @Service est réservée aux services et @Repository aux Dao, c'est la bonne séparation en couche qui me pousse à avancer ma précédente déclaration.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Ah, je comprends mieux les nuances désormais. La doc et les manuels en anglais ne disent pas tous la même chose, c'est pas très réconfortant pour un débutant dans le domaine souvent :-' (J'ai l'habitude de faire du Django en Python ou Symfony en PHP, où on a pas ces diverses couches aussi structuré mais juste un MVC)

  9. #9
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    Citation Envoyé par ray_fab Voir le message
    http://JeitEmgie ok pour ce que tu dis mais quand on fait les choses bien, tous les problèmes d'ordres transversaux sont délégués aux services et l'accès à la base de données aux Dao, dans ce cas l'annotation @Service est réservée aux services et @Repository aux Dao, c'est la bonne séparation en couche qui me pousse à avancer ma précédente déclaration.
    Ce n'est pas le fait de mettre telle ou telle annotation sur une classe qui créé de facto et ex nihilo des couches dans votre application : ce sont les design patterns utilisés et les taxonomies exprimées qui font que la séparation des fonctionnalités est réalisée.

    Les différentes annotations viennent ensuite pour appuyer l'expression de cette séparation et non pour la réaliser.
    Cette séparation ainsi exprimée, des outils intervenant ensuite peuvent en tirer profit pour ajouter des fonctionnalités d'utilité transversale : c'est le cas de @Repository qui ajoute à @Component la demande de traduction des exceptions, mais c'est l'outil de scanning des beans de Spring qui rajoute cette traduction des exceptions.

    Rien ne vous empêche d'annoter @Repository un service qui n'est pas à proprement parler un DAO mais pour lequel il serait important d'avoir une traduction des exceptions en DataAccessException (et que vous n'avez pas envie de refaire un Aspect qui existe déjà) et d'annoter un DAO en @Service parce que soit la couche d'accès n'a pas besoin de cette traduction des exceptions ou qu'elle est contre-productive dans le contexte.
    Autrement dit, c'est parce que vous voulez - acte conscient - la traduction des exceptions que vous annotez votre DAO @Repository et non pas parce que c'est un DAO et que cela vous donne bonne conscience en faisant "comme on dit que c'est bien de le faire".

    De même, rien ne vous empêche de définir vos propres annotations dérivées de @Component avec les Aspects associés pour réaliser toute autre fonctionnalité désirée : à partir du moment que vous dérivez de @Component, l'objet ainsi annoté serait traité par Spring.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [RegEx] Remplacer URL par des liens sauf dans les balises
    Par raph37 dans le forum Langage
    Réponses: 7
    Dernier message: 19/10/2013, 19h31
  2. Réponses: 4
    Dernier message: 25/09/2013, 17h35
  3. [RegEx] Remplacer les <br/> par des sauts à la ligne dans des zones de texte
    Par doncandid dans le forum Langage
    Réponses: 5
    Dernier message: 17/03/2010, 17h59
  4. Réponses: 3
    Dernier message: 09/03/2009, 09h22
  5. Réponses: 5
    Dernier message: 13/11/2007, 22h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo